{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Special Matrices"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"using LinearAlgebra"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"The 2D arrays seen so far have been general, that is, that can be used to represent arbitrary matrices. Many applications lead to matrices with special structures or properties, and Julia defines a number of specialized matrix representations for this. The main reason for using these is to obtain better performance (which can make a very big difference), but they are also useful to e.g. ensure correctness of codes by enforcing known properties.\n",
"\n",
"\n",
"| Type | Description |\n",
"|:------------------- |:--------------------------------------------------------------------------------------------- |\n",
"| Symmetric | [Symmetric matrix](https://en.wikipedia.org/wiki/Symmetric_matrix) |\n",
"| Hermitian | [Hermitian matrix](https://en.wikipedia.org/wiki/Hermitian_matrix) |\n",
"| UpperTriangular | Upper [triangular matrix](https://en.wikipedia.org/wiki/Triangular_matrix) |\n",
"| UnitUpperTriangular | Upper [triangular matrix](https://en.wikipedia.org/wiki/Triangular_matrix) with unit diagonal |\n",
"| LowerTriangular | Lower [triangular matrix](https://en.wikipedia.org/wiki/Triangular_matrix) |\n",
"| UnitLowerTriangular | Lower [triangular matrix](https://en.wikipedia.org/wiki/Triangular_matrix) with unit diagonal |\n",
"| Tridiagonal | [Tridiagonal matrix](https://en.wikipedia.org/wiki/Tridiagonal_matrix) |\n",
"| SymTridiagonal | Symmetric tridiagonal matrix |\n",
"| Bidiagonal | Upper/lower [bidiagonal matrix](https://en.wikipedia.org/wiki/Bidiagonal_matrix) |\n",
"| Diagonal | [Diagonal matrix](https://en.wikipedia.org/wiki/Diagonal_matrix) |\n",
"| UniformScaling | [Uniform scaling operator](https://en.wikipedia.org/wiki/Uniform_scaling) |"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"For example, if you know that your matrix is both symmetric and tridiagonal, you can use the `SymTridiagonal` type. The example below shows how to generate a famous matrix which is very common in applications:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"5×5 SymTridiagonal{Float64, Vector{Float64}}:\n",
" 2.0 -1.0 ⋅ ⋅ ⋅ \n",
" -1.0 2.0 -1.0 ⋅ ⋅ \n",
" ⋅ -1.0 2.0 -1.0 ⋅ \n",
" ⋅ ⋅ -1.0 2.0 -1.0\n",
" ⋅ ⋅ ⋅ -1.0 2.0"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"T = SymTridiagonal(2ones(5), -ones(4))"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"The matrix operations defined above will work just as before on these specialized types, but likely be much more efficient. For example:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"5×5 Matrix{Float64}:\n",
" 14.0 -14.0 6.0 -1.0 0.0\n",
" -14.0 20.0 -15.0 6.0 -1.0\n",
" 6.0 -15.0 20.0 -15.0 6.0\n",
" -1.0 6.0 -15.0 20.0 -14.0\n",
" 0.0 -1.0 6.0 -14.0 14.0"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"T * randn(5) # Matrix-vector multiplication\n",
"T^3 # Matrix cube"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## The identity matrix\n",
"\n",
"The identity matrix $I$ is so commonly used, that it has a special syntax which supports some additional performance improvements. In its simplest form, you can simply use the `I` operator and it will behave as expected:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"5×5 SymTridiagonal{Float64, Vector{Float64}}:\n",
" 4.0 -1.0 ⋅ ⋅ ⋅ \n",
" -1.0 4.0 -1.0 ⋅ ⋅ \n",
" ⋅ -1.0 4.0 -1.0 ⋅ \n",
" ⋅ ⋅ -1.0 4.0 -1.0\n",
" ⋅ ⋅ ⋅ -1.0 4.0"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"T + 2I # OK, since T is 3-by-3"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"If you want to actually create an identity matrix, you have to specify the element type and the dimensions:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"4×4 Matrix{Float64}:\n",
" 1.0 0.0 0.0 0.0\n",
" 0.0 1.0 0.0 0.0\n",
" 0.0 0.0 1.0 0.0\n",
" 0.0 0.0 0.0 1.0"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"I4 = Matrix{Float64}(I, 4, 4)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"but this is often not necessary since the `I` operator can be used in expressions, as shown above."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.9.2",
"language": "julia",
"name": "julia-1.9"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.9.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}