Vectors and Matrices in Sage

In the previous section we have been assuming that the matrix elements are real or complex numbers from the field \(\,R\,\) or \(\,C,\,\) respectively. Actually, the operations on matrices are possible, and properties of these operations are preserved, even though elements belong to a simpler structure - a ring with identity. In Sage the algebra of polynomials or matrices is built just over a ring rather than over a field.

Below we list the most important rings applied in Sage:

\(\qquad\qquad\quad\text{Symbol}\):
Description \(\,\) and \(\,\) name in Sage:
\(\qquad\qquad\qquad\) ZZ
Ring of integer numbers:
Integer Ring
\(\qquad\qquad\qquad\) QQ
Field of rational numbers:
Rational Field
\(\qquad\qquad\qquad\) RR
Field of real numbers:
Real Field with 53 bits of precision
\(\qquad\qquad\qquad\) CC
Field of complex numbers:
Complex Field with 53 bits of precision
\(\qquad\qquad\qquad\) RDF
Field of real numbers
with double precision :
Real Double Field
\(\qquad\qquad\qquad\) CDF
Field of complex numbers
with double precision:
Complex Double Field
\(\qquad\qquad\) RealField(12)
Field of real numbers
with the given precision:
Real Field with 12 bits of precision
\(\qquad\qquad\) ComplexField(248)
Field of complex numbers
with the given precision:
Complex Field with 248 bits of precision
\(\qquad\qquad\qquad\) SR
Symbolic ring:
Symbolic Ring

There are two strategies of calculations on vectors and matrices:

  • exact linear algebra: elements of vectors and matrices belong to the sets ZZ, QQ or SR; calculations are exact, but not all can be performed and their efficiency is limited;

  • numerical linear algebra: elements of vectors and matrices are numbers of finite precision from fields RR, CC, RDF or CDF; the obtained results are rounded and errors from successive roundings may accumulate.

Note

The base ring of a matrix, whose elements depend on any variables, is the symbolic ring SR. If numerical values are assigned to these variables, the base ring of the matrix will be still SR, though the matrix will be composed of numbers only. To make numerical methods applicable, the function change_ring() is to be explicitly used.

Example. \(\\\) The matrix \(\,\boldsymbol{A}\,\) depends on the variable \(\,\) phi \(\,\) and its base ring is Symbolic Ring:

sage: var('phi')
sage: A = matrix([[cos(phi),-sin(phi)],
                  [sin(phi), cos(phi)]])

sage: print A, "\n"
sage: print "Base ring of the matrix A:", A.base_ring()

[ cos(phi) -sin(phi)]
[ sin(phi)  cos(phi)]

Base ring of the matrix A: Symbolic Ring

After substitution \(\,\) phi = 0.25 \(\,\) the base ring is still Symbolic Ring:

sage: B = A.subs(phi=0.25)

sage: print B.n(digits=4), "\n"
sage: print "Base ring of the matrix B:", B.base_ring()

[ 0.9689 -0.2474]
[ 0.2474  0.9689]

Base ring of the matrix B: Symbolic Ring

Only the explicit change of ring returns the purely numerical matrix:

sage: C = B.change_ring(RDF)

sage: print C.n(digits=4), "\n"
sage: print "Base ring of the matrix C:", C.base_ring()

[ 0.9689 -0.2474]
[ 0.2474  0.9689]

Base ring of the matrix C: Real Double Field

Sage supports the ‘row’ (as opposed to ‘column’) approach to vectors and matrices. Vectors are displayed ‘horizontally’, and matrix is a sequence (list) of rows. It is to be pointed out that in Sage a vector is an object different from a one-row as well as from a one-column matrix: it is just a finite sequence of elements of a ring. It can be transformed into an above-mentioned matrix only by application of the appropriate function.

Creation of Vectors and Matrices

In Sage vectors and matrices are objects of the Python language, that belong to the respective classes. These objects are created using the constructors vector() and matrix().

Below we apply the standard syntax of the object-oriented programming: if the function func() is a method of a class, then the result of its application to the object obj of this class is denoted by obj.func().

Vectors.

The constructor vector() can be called in several ways. Usually, the arguments are:

  • ring - a base ring (or field) which contains all the elements of the vector

  • degree - number of elements

  • object - a list containing entries of the vector

In the examples below, the method base_ring() gives the ring (or field) over which vectors have been built, and parent() yields the class, to which the vectors belong.

sage: # A generic use of the constructor;
      # the degree specification is actually redundant:

sage: v = vector(QQ, 3, [1.2, 3.6, -0.48])
sage: print v; print v.base_ring(); v.parent()

(6/5, 18/5, -12/25)
Rational Field
Vector space of dimension 3 over Rational Field
sage: # Specification of the base ring is optional;
      # the default is the integer ring ZZ:

sage: v = vector([3, 5, -11])
sage: print v; v.base_ring()

(3, 5, -11)
Integer Ring
sage: # if no entries of the object are specified,
      # the vector is populated with zeros:

sage: v = vector(RDF,5)
sage: print v; v.parent()

(0.0, 0.0, 0.0, 0.0, 0.0)
Vector space of dimension 5 over Real Double Field

Vectors may also be created as instances of the \(\,\) VectorSpace() \(\,\) class:

sage: VS = VectorSpace(QQ,3)
sage: v = VS([-1, 4, 3.5])
sage: print VS; v

Vector space of dimension 3 over Rational Field
(-1, 4, 7/2)

Matrices.

The constructor matrix() acts similarly to vector(). Its main arguments are:

  • ring – the base ring for the entries of the matrix; if not determined, defaults to ZZ

  • nrows – the number of rows in the matrix

  • ncols – the number of columns in the matrix; defaults to nrows if not specified

  • entries - a flat list of elements, a list of lists (i.e., a list of rows) or a list of Sage vectors

sage: # A default constructor creates an empty matrix:
sage: M = matrix()
sage: print M; print M.base_ring(); M.parent()

[]
Integer Ring
Full MatrixSpace of 0 by 0 dense matrices over Integer Ring
sage: # A generic use of the matrix constructor:
sage: M1 = matrix(RDF, 2,3, [1,2,3,4,5,6])
sage: M2 = matrix(RDF, [[1,2,3],[4,5,6]])
sage: print M1, "\n"; print M2, "\n"; M1.parent()

[1.0 2.0 3.0]
[4.0 5.0 6.0]

[1.0 2.0 3.0]
[4.0 5.0 6.0]

Full MatrixSpace of 2 by 3 dense matrices over Real Double Field
sage: # Construction of a square matrix:
sage: M = matrix(3,range(9)); M

[0 1 2]
[3 4 5]
[6 7 8]
sage: # Matrix given as a list of vectors:

sage: v1 = vector([1,2,3,-1]);\
      v2 = vector([4,5,6,-2]);\
      v3 = vector([7,8,9,-3])
sage: M = matrix([v1,v2,v3]); M

[ 1  2  3 -1]
[ 4  5  6 -2]
[ 7  8  9 -3]

By analogy with VectorSpace(), the command MatrixSpace() creates the space of matrices of definite dimensions over a given ring. The mandatory arguments are base ring and number of rows (the number of columns, by default equal to the number of rows, is optional). The appropriate methods give access to attributes of the space such as dimension, dimensions of matrices, basis.

sage: MS32 = MatrixSpace(ZZ,3,2)
sage: print MS32; print MS32.dimension();\
      print MS32.dims(); MS32.basis()

Full MatrixSpace of 3 by 2 dense matrices over Integer Ring
6
(3, 2)
[
[1 0]  [0 1]  [0 0]  [0 0]  [0 0]  [0 0]
[0 0]  [0 0]  [1 0]  [0 1]  [0 0]  [0 0]
[0 0], [0 0], [0 0], [0 0], [1 0], [0 1]
]
sage: # Mat() is an alias for MatrixSpace():

sage: MS = Mat(RealField(12),2)
sage: print MS; MS.basis()

Full MatrixSpace of 2 by 2 dense matrices over Real Field with 12 bits
of precision
[
[1.00  0.000]  [0.000 1.00 ]  [0.000 0.000]  [0.000 0.000]
[0.000 0.000], [0.000 0.000], [1.00  0.000], [0.000 1.00 ]
]

A space of matrices being at disposal, the matrices may be created as its instances:

sage: MS22 = Mat(QQ,2)
sage: MS23 = Mat(QQ,2,3)

sage: A = MS22([1,2,3,4])
sage: B = MS23([1,2,3,4,5,6])

sage: A, B, A*B # matrices A, B and the product AB

(
[1 2]  [1 2 3]  [ 9 12 15]
[3 4], [4 5 6], [19 26 33]
)

Alternatively, the matrix() statement is used as a method belonging to the matrix class:

sage: MS33 = Mat(QQ,3)
sage: MS34 = Mat(QQ,3,4)
sage: A = MS33.matrix(range(9))
sage: B = MS34.matrix(range(12))
sage: A, B, A*B # matrices A, B and the product AB

(
[0 1 2]  [ 0  1  2  3]  [ 20  23  26  29]
[3 4 5]  [ 4  5  6  7]  [ 56  68  80  92]
[6 7 8], [ 8  9 10 11], [ 92 113 134 155]
)

In addition to the universal constructor matrix(), Sage offers several specialized constructors creating some specific matrices in a ready form:

sage: O = zero_matrix(QQ,3,2)
sage: I = identity_matrix(3)
sage: J = ones_matrix(3,4)
sage: D = diagonal_matrix([1,2,3])
sage: R = random_matrix(QQ, 3,3, algorithm='diagonalizable')
sage: E = elementary_matrix(QQ, 3, row1=1, row2=2, scale=2)
sage: O, I, J, D, R, E

(
[0 0]  [1 0 0]  [1 1 1 1]  [1 0 0]  [  8  10 -20]  [1 0 0]
[0 0]  [0 1 0]  [1 1 1 1]  [0 2 0]  [-36 -22  24]  [0 1 2]
[0 0], [0 0 1], [1 1 1 1], [0 0 3], [-18 -10  10], [0 0 1]
)

Properties of Vectors and Matrices

Indices.

In the traditional mathematical notation the numbering of elements of a sequence starts from one. Thus a vector of size \(\,n\ \) and a matrix with \(\,m\,\) rows and \(\,n\,\) columns read as follows:

\[\boldsymbol{v}\ =\ [v_i]_n\ =\ (\,v_1,\ v_2,\ \ldots,\ v_n\,)\,,\]
\[\begin{split}\boldsymbol{A}\ \,=\ \,[a_{ij}]_{m\times n}\ \,=\ \, \left[\begin{array}{cccc} a_{11} & a_{12} & \ldots & a_{1n} \\ a_{21} & a_{22} & \ldots & a_{2n} \\ \ldots & \ldots & \ldots & \ldots \\ a_{m1} & a_{m2} & \ldots & a_{mn} \end{array}\right]\,.\end{split}\]

In Sage the starting number of elements of vectors as well as that of rows and columns of matrices is zero. Therefore vectors and matrices have the following index structure:

\[\boldsymbol{v}\ =\ (\, v[0],\ v[1],\ \ldots,\ v[n-1]\, )\,,\]
\[\begin{split}\boldsymbol{A}\quad=\quad\left(\begin{array}{cccc} A[0,0] & A[0,1] & \ldots & A[0,n-1] \\ A[1,0] & A[1,1] & \ldots & A[1,n-1] \\ \ldots & \ldots & \ldots & \ldots \\ A[m-1,0] & A[m-1,1] & \ldots & A[m-1,n-1] \end{array}\right)\,.\end{split}\]

Let \(\,\boldsymbol{v}\,\) be an \(\,n\)-size vector: \(\ \boldsymbol{v}\ =\ (\, v_1,\ v_2,\ \ldots,\ v_n\,)\ =\ (\, v[0],\ v[1],\ \ldots,\ v[n-1]\, ).\ \) The relation between the two numbering conventions is thus such that \(\,v_i\,=\,v[i-1]:\ \) the \(\,i\)-th element of \(\ \boldsymbol{v}\ \) is equal to the \(\,[i-1]\)-th element of this vector, \(\ i=1,2,\ldots,n.\ \) Analogous rules hold for matrices. Below these relations are illustrated by examples:

sage: v = vector([-1, 5, 3, -4, 8])
sage: print 'Vector v and its selected elements:', '\n'
sage: print 'v =', v, '\n\nv[0] =', v[0], '  v[3] =', v[3]

Vector v and its selected elements:

v = (-1, 5, 3, -4, 8)

v[0] = -1   v[3] = -4
sage: A = matrix([[0,2,4,6],[1,3,5,7],[2,4,6,8]])

sage: print A

sage: print '\nSelected row, column and elements:'

sage: print '\nSecond row   = row number [1]    = A.row(1)    =',\
            A.row(1)

sage: print '\nFirst column = column number [0] = A.column(0) =',\
            A.column(0)

sage: print '\nA[0,0] =', A[0,0],\
            '  A[1,3] =', A[1,3],\
            '  A[2,2] =', A[2,2]

[0 2 4 6]
[1 3 5 7]
[2 4 6 8]

Selected row, column and elements:

Second row   = row number [1]    = A.row(1)    = (1, 3, 5, 7)

First column = column number [0] = A.column(0) = (0, 1, 2)

A[0,0] = 0   A[1,3] = 7   A[2,2] = 6

Finally, we present two examples of the situation, when matrix elements are a function of their indices. \(\,\boldsymbol{A}\ \) is the general rectangular matrix of the given dimensions, with elements \(\,a_{ij};\\\) \(\ \boldsymbol{B}\ \) is the complex matrix (\(\,i\,\) is the imaginary unit) with elements

\[\begin{split}b_{kl}\,=\,k+l\cdot i\,,\qquad \begin{array}{l} k\,=\,1,2,\ldots,m\,; \\ \,l\,=\,1,2,\ldots,n.\end{array}\end{split}\]

Slicing.

Slicing extracts selected elements from a sequence, thus creating sub-sequences. This technique is applicable, among others, to lists, vectors and matrices (a matrix being a list of rows). In particular, if \(\,L\ \) is a list of size \(\,n,\ \) then for \(\ p = 0, 1, ..., n-1;\) \(\ q = 1, 2, ..., n;\) \(\ p<q:\)

  • L[p] \(\ \) - \(\ \) the [p]-th, \(\ \) that is the (p+1)-th, \(\ \) element of \(\,L\);
    L[-2], L[-1] \(\ \) - \(\ \) the next-to-last and last elements of \(\,L\);
  • L[p:q] \(\ \) - \(\ \) sublist of \(\ q-p\ \) elements of \(\,L,\ \)
    starting at the [p]-th \(\ \) and \(\ \) ending with the [q-1]-th \(\ \) element;
  • L[:q] \(\ \) - \(\ \) sublist of \(\,q\ \) elements of \(\,L,\ \)
    starting at the beginning of the list and ending with the [q-1]-th element;
  • L[p:] \(\ \) - \(\ \) sublist of \(\ n-p\ \) elements of \(\ L,\ \)
    starting at the [p]-th element and going to the end;
  • L[p:q:r] \(\ \) - \(\ \) sublist of elements of \(\,L\ \) with numbers from [p] to [q-1] inclusively,
    with the step (slicing increment) \(\ r.\)
sage: M = matrix(4,5,range(20))
sage: # Slicing yields a matrix composed of:
sage: A = M[1:3]     # rows [1]., [2].
sage: B = M[:,2:5]   # columns [2]., [3]., [4].
sage: C = M[1:3,2:5] # elements of rows [1]., [2].
                     #  and columns [2]., [3]., [4].
sage: D = M[1:,::2]  # elements of rows [1]., [2]., [3].
                     #  and columns [0]., [2]., [4].
sage: print M
sage: A, B, C, D

[ 0  1  2  3  4]
[ 5  6  7  8  9]
[10 11 12 13 14]
[15 16 17 18 19]
(
                  [ 2  3  4]
                  [ 7  8  9]              [ 5  7  9]
[ 5  6  7  8  9]  [12 13 14]  [ 7  8  9]  [10 12 14]
[10 11 12 13 14], [17 18 19], [12 13 14], [15 17 19]
)

Note

\(\,\)

Let \(\,A\,\) be an \(\ m \times n\ \) matrix over a ring \(\,P,\ i=0,1,\ldots,m-1;\ j=0,1,\ldots,n-1. \\\)

Then its [i]-th row may be obtained in three ways:

  • A[i] \(\ \) or \(\ \) A.row(i) \(\ \) - \(\ \) as an \(\,n\)-size vector over \(\,P;\)

  • A[i,:] \(\ \) - \(\ \) as an \(\ 1\)-row matrix over \(\,P\ \) with \(\,n\ \) elements. \(\\\)

For the [j]-th column there are two formulae:

  • A.column(j) \(\ \) - \(\ \) as a vector of size \(\,m\ \) over \(\,P\ \) (written horizontally);

  • A[:,j] \(\ \) - \(\ \) as a \(\,1\)-column matrix over \(\,P\ \) with \(\,m\ \) elements.

The above rules are illustrated by the following example:

sage: A = matrix(3,4,[-1,0,2,1,-1,7,-1,1,1,-1,3,2])
sage: print A, '\n'

sage: print A[2]; print type(A[2]), '\n'
sage: print A.row(2); print type(A.row(2)), '\n'
sage: print A[2,:]; print type(A[2,:]), '\n'
sage: print A.column(1); print type(A.column(1)), '\n'
sage: print A[:,1]; print type(A[:,1])

[-1  0  2  1]
[-1  7 -1  1]
[ 1 -1  3  2]

(1, -1, 3, 2)
<type 'sage.modules.vector_integer_dense.Vector_integer_dense'>

(1, -1, 3, 2)
<type 'sage.modules.vector_integer_dense.Vector_integer_dense'>

[ 1 -1  3  2]
<type 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'>

(0, 7, -1)
<type 'sage.modules.vector_integer_dense.Vector_integer_dense'>

[ 0]
[ 7]
[-1]
<type 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'>

Operations on Vectors and Matrices

Linear Combination of Vectors.

The addition and scalar multiplication of \(\,n\)-size vectors over a ring \(\,P\,\) are analogous to the operations on column vectors over a field \(\,K.\ \) If a vector \(\ \boldsymbol{w} = (w_1,w_2,\ldots,w_n)\ \) is the linear combination of vectors \(\,\boldsymbol{x} = (x_1,x_2,\ldots,x_n)\ \) and \(\ \,\boldsymbol{y} = (y_1,y_2,\ldots,y_n):\ \)

\[\boldsymbol{w}\ =\ a\,\boldsymbol{x}\, +\, b\,\boldsymbol{y}\,, \qquad a,b\in P,\]

then its elements are given by

\[w_i\ =\ a\,x_i\, +\, b\,y_i\,,\qquad i\,=\,1,2,\ldots,n.\]

The \(\,n\)-element vectors over a ring \(\,P\,\) form a free module with respect to vector addition and scalar multiplication (for \(\,n\)-size vectors over a field the module is a vector space).

Dot Product of vectors.

Dot product (scalar product) of two vectors of the same size is defined as the sum of products of corresponding elements:

\[\boldsymbol{x} \cdot \boldsymbol{y} \ \,:\,=\ \, \sum_{i=1}^n\,x_i\,y_i\ \,=\ \, x_1\,y_1\,+\,x_2\,y_2\,+\,\ldots\,+\,x_n\,y_n\,.\]

This is an example of a linear combination and the dot product of vectors:

sage: x = vector([-1,2,5])
sage: y = vector([3,0,4])

# Linear combination w of vectors x, y with coefficients 3, -2:
sage: w = 3*x-2*y

# Dot product p of vectors x, y:
sage: p = x*y

sage: show(table([[3,'$\cdot$',x,'-',2,'$\cdot$',y,'=',w]]))
sage: show(table([[x,'$\cdot$',y,'=',p]]))

\(\begin{array}{ccccccccc} 3 & \cdot & \left(-1,\,2,\,5\right) & - & 2 & \cdot & \left(3,\,0,\,4\right) & = & \left(-9,\,6,\,7\right)\end{array}\)

\(\begin{array}{ccccc} \left(-1,\,2,\,5\right) & \cdot & \left(3,\,0,\,4\right) & = & 17 \end{array}\)

The dot product of two vectors \(\,\boldsymbol{x},\,\boldsymbol{y}\ \) is connected with the matrix product of the one-row matrix obtained from \(\,\boldsymbol{x}\,\) by the one-column matrix obtained from \(\,\boldsymbol{y}\).

A vector may be transformed into a one-row or one-column matrix by means of the methods row() or column(), respectively.

sage: x = vector([-1,2,5])
sage: y = vector([3,0,4])

sage: x_row = x.row()
sage: y_col = y.column()

sage: p = x_row * y_col
sage: table([[x_row,'*',y_col,'=',p]])

\(\begin{array}{ccccc} \left(\begin{array}{ccc} -1 & 2 & 5 \end{array}\right) & \ast & \left(\begin{array}{c} 3 \\ 0 \\ 4 \end{array}\right) & = & (17) \end{array}\)

\(\,\)

Products of a matrix and a vector.

If \(\ \boldsymbol{x}\ \) is an \(\ n\)-element vector, \(\ \) and \(\ \boldsymbol{A}\ \) - \(\ \) a square matrix of size \(\ n\):

\[\begin{split}\boldsymbol{x}\ =\ (x_1,x_2,\ldots,x_n)\,,\qquad \boldsymbol{A}\ =\ \left[\begin{array}{cccc} a_{11} & a_{12} & \ldots & a_{1n} \\ a_{21} & a_{22} & \ldots & a_{2n} \\ \ldots & \ldots & \ldots & \ldots \\ a_{n1} & a_{n2} & \ldots & a_{nn} \end{array}\right]\,,\end{split}\]

then there exist products \(\ \ \boldsymbol{v} = \boldsymbol{x} \cdot \boldsymbol{A}\ \ \) and \(\ \ \boldsymbol{w} = \boldsymbol{A} \cdot \boldsymbol{x}\,.\)

Both results, \(\ \boldsymbol{v}\ \) and \(\ \boldsymbol{w},\ \) are vectors, and

\[ \begin{align}\begin{aligned}v_j\ :\,=\ \sum_{i=1}^n\,x_i\,a_{ij}\ =\ x_1\,a_{1j}\,+\,x_2\,a_{2j}\,+\,\ldots\,+\,x_n\,a_{nj}\,, \qquad j\,=\,1,2,\ldots,n,\\w_i\ :\,=\ \sum_{j=1}^n\,a_{ij}\,x_j\ =\ a_{i1}\,x_1\,+\,a_{i2}\,x_2\,+\,\ldots\,+\,a_{in}\,x_n\,, \qquad i\,=\,1,2,\ldots,n.\end{aligned}\end{align} \]

\(\ \)

This is illustrated by the example:

sage: x = vector(range(3))
sage: A = matrix(3,range(9))

sage: v = x*A; w = A*x

sage: show(table([[x,'*',A,'=',v]]))
sage: show(table([[A,'*',x,'=',w]]))

\(\begin{array}{ccccc} \left(0,\,1,\,2\right) & \ast & \left(\begin{array}{rrr} 0 & 1 & 2 \\ 3 & 4 & 5 \\ 6 & 7 & 8 \end{array}\right) & = & \left(15,\,18,\,21\right) \end{array}\)

\(\begin{array}{ccccc} \left(\begin{array}{rrr} 0 & 1 & 2 \\ 3 & 4 & 5 \\ 6 & 7 & 8 \end{array}\right) & \ast & \left(0,\,1,\,2\right) & = & \left(5,\,14,\,23\right) \end{array}\)

Note that if we replace vectors by one-row matrices, the first equation will remain true, while the second will become senseless (the product of a square matrix by a one-row matrix is not defined):

sage: x = vector(range(3))
sage: A = matrix(3,range(9))

sage: x_row = x.row()

sage: v_row = x_row * A
sage: show(table([[x_row,'*',A,'=',v_row]]))

sage: w_row = A * x_row
sage: show(table([[A,'*',x_row,'=',w_row]]))

\(\begin{array}{ccccc} \left(\begin{array}{rrr} 0 & 1 & 2 \end{array}\right) & \ast & \left(\begin{array}{rrr} 0 & 1 & 2 \\ 3 & 4 & 5 \\ 6 & 7 & 8 \end{array}\right) & = & \left(\begin{array}{rrr} 15 & 18 & 21 \end{array}\right) \end{array}\)


TypeError: unsupported operand parent(s) for '*': 'Full MatrixSpace of 3 by 3 dense matrices over Integer Ring' and 'Full MatrixSpace of 1 by 3 dense matrices over Integer Ring'

To get the correct matrix version of the second equation, vectors are to be replaced by one-column matrices:

sage: x = vector(range(3))
sage: A = matrix(3,range(9))

sage: x_col = x.column()
sage: w_col = A * x_col

sage: show(table([[A,'*',x_col,'=',w_col]]))

\(\begin{array}{ccccc} \left(\begin{array}{rrr} 0 & 1 & 2 \\ 3 & 4 & 5 \\ 6 & 7 & 8 \end{array}\right) & \ast & \left(\begin{array}{r} 0 \\ 1 \\ 2 \end{array}\right) & = & \left(\begin{array}{r} 5 \\ 14 \\ 23 \end{array}\right) \end{array}\)

In passing we note that the first equation may be rewritten in the column version by transpose of both sides (transpose of a product of matrices yields the product of transposed factors in reverse order):

sage: x = vector(range(3))
sage: A = matrix(3,range(9))

sage: x_col = x.column()
sage: A_t = A.transpose()

sage: v_col = A_t * x_col

sage: table([[A_t,'*',x_col,'=',v_col]])

\(\begin{array}{ccccc} \left(\begin{array}{rrr} 0 & 3 & 6 \\ 1 & 4 & 7 \\ 2 & 5 & 8 \end{array}\right) & \ast & \left(\begin{array}{r} 0 \\ 1 \\ 2 \end{array}\right) & = & \left(\begin{array}{r} 15 \\ 18 \\ 21 \end{array}\right) \end{array}\)

\(\;\)

Product of matrices.

Sage of course deals with the multiplication of any two matrices with appropriate dimensions (the number of columns of the first matrix must equal the number of rows of the second). A few examples (in which one factor was a 1-row or 1-column matrix) have been already given in this section. Here is another example:

sage: A = matrix(2,3,range(6))
sage: B = matrix(3,range(9))
sage: C = A*B
sage: table([[A,'*',B,'=',C]])

\(\begin{array}{ccccc} \left(\begin{array}{rrr} 0 & 1 & 2 \\ 3 & 4 & 5 \end{array}\right) & \ast & \left(\begin{array}{rrr} 0 & 1 & 2 \\ 3 & 4 & 5 \\ 6 & 7 & 8 \end{array}\right) & = & \left(\begin{array}{rrr} 15 & 18 & 21 \\ 42 & 54 & 66 \end{array}\right) \end{array}\)

\(\;\)

An attempt to multiply matrices with incompatible dimensions results in an error:

sage: A = matrix(3,range(9))
sage: B = matrix(2,3,range(6))

sage: C = A*B

TypeError: unsupported operand parent(s) for '*': 'Full MatrixSpace of 3 by 3 dense matrices over Integer Ring' and 'Full MatrixSpace of 2 by 3 dense matrices over Integer Ring'

The above examples show that the symbols of addition, subtraction and multiplication have context-sensitive meaning.

Specifically, the symbols \(\,\)+/-\(\,\) denote addition/subtraction of numbers (scalars), vectors or matrices; \(\ \) the symbol \(\,\)*\(\,\) denotes multiplication of numbers, multiplication of a vector by a number, dot product of two vectors, multiplication of a vector by a matrix and vice versa, or product of two matrices.

Block Matrices

Every matrix with dimensions at least two can be divided into four (or more) rectangular blocks. Such division being performed, we say of a block matrix. It turns out that the rules of multiplication of block matrices are completely analogous to those of elementary matrices:

(1)\[\begin{split}\left[\begin{array}{c|c} \boldsymbol{A} & \boldsymbol{B} \\ \hline \boldsymbol{C} & \boldsymbol{D} \end{array}\right] \left[\begin{array}{c} \boldsymbol{X} \\ \hline \boldsymbol{Y} \end{array}\right] \ =\ \left[\begin{array}{c} \boldsymbol{A} \boldsymbol{X} + \boldsymbol{B} \boldsymbol{Y} \\ \hline \boldsymbol{C} \boldsymbol{X} + \boldsymbol{D} \boldsymbol{Y} \end{array}\right]\,.\end{split}\]

The blocks \(\ \boldsymbol{A},\boldsymbol{B}, \boldsymbol{C},\boldsymbol{D},\boldsymbol{X},\boldsymbol{Y}\ \) are here any matrices provided that their dimensions make the matrix multiplications possible.

Typically, using equation (1) does not reduce the volume of operations. However, when there are some zero or identity blocks, the calculations may be relevantly simplified. Consider e.g. the case, when there are two zero blocks (denoted by \(\ \boldsymbol{O}\)). \(\ \) Then

\[\begin{split}\left[\begin{array}{c|c} \boldsymbol{A} & \boldsymbol{O} \\ \hline \boldsymbol{O} & \boldsymbol{D} \end{array}\right] \left[\begin{array}{c} \boldsymbol{X} \\ \hline \boldsymbol{Y} \end{array}\right] \ =\ \left[\begin{array}{c} \boldsymbol{A} \boldsymbol{X} \\ \hline \boldsymbol{D} \boldsymbol{Y} \end{array}\right]\end{split}\]

Sage has several functions destined to handle block matrices.

The block_matrix() command takes a list of submatrices to add as blocks, optionally preceding it by a ring and the number of block rows and block columns. Its arguments are:

  • ring \(\ -\ \) the base ring

  • nrows \(\ -\ \) the number of block rows

  • ncols \(\ -\ \) the numbber of block columns

  • blocks \(\ -\ \) submatrices to be assembled

  • subdivide \(\ -\ \) boolean, whether or not to add subdivision information to the matrix

sage: A = matrix(QQ, 2, 3, [3,9,6,10,12,15])
sage: block_matrix([[1,A], [0,1]])

[ 1  0| 3  9  6]
[ 0  1|10 12 15]
[-----+--------]
[ 0  0| 1  0  0]
[ 0  0| 0  1  0]
[ 0  0| 0  0  1]

Here the 0 and 1 entry have been interpreted as the zero and identity matrix of compatible dimensions. The subdivision information (horizontal and vertical lines) may be lifted by putting subdivision = False.

The subdivide() method divides a matrix into blocks, which can then be extracted. \(\\\) The arguments are

  • row_lines - None, an integer, or a list of integers

  • col_lines - None, an integer, or a list of integers

The subdivision() method extracts a given block from a matrix, whereas subdivision_entry() yields a selected element.

The following examples should make their functioning clear:

sage: A = matrix(QQ, 5, range(25))
sage: A.subdivide(3,2)
sage: print A, '\n'
sage: print A.subdivision(1,0), '\n'
sage: A.subdivision_entry(0,1,2,1)

[ 0  1| 2  3  4]
[ 5  6| 7  8  9]
[10 11|12 13 14]
[-----+--------]
[15 16|17 18 19]
[20 21|22 23 24]

[15 16]
[20 21]

13
sage: A = matrix(6,range(36))
sage: A.subdivide([1,3,5],[2,4])
sage: print A, '\n'
sage: A.subdivision(2,1)

[ 0  1| 2  3| 4  5]
[-----+-----+-----]
[ 6  7| 8  9|10 11]
[12 13|14 15|16 17]
[-----+-----+-----]
[18 19|20 21|22 23]
[24 25|26 27|28 29]
[-----+-----+-----]
[30 31|32 33|34 35]

[20 21]
[26 27]

Experiment with Sage! \(\\\)

The program given below uses the function block_matrix() to compose a matrix of the given submatrices.

The reader is encouraged to test equation (1) for various components of the block matrices.