]>
gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/matrix_vector.py
62b75fd43e2299d605d7000f7c741af6e1bf6690
2 There is an explicit isomorphism between all finite-dimensional vector
3 spaces. In particular, there is an isomorphism between the m-by-n
4 matrices and `$R^(m \times n)$`. Since most vector operations are not
5 available on Sage matrices, we have to go back and forth between these
6 two vector spaces often.
10 from sage
.matrix
.matrix_space
import is_MatrixSpace
13 return vector(m
.base_ring(), m
.list())
15 def basis_representation(M
):
17 Return the forward (``MatrixSpace`` -> ``VectorSpace``) and
18 inverse isometries, as a pair, that take elements of the given
19 ``MatrixSpace`` `M` to their representations as "long vectors,"
22 The argument ``M`` can be either a ``MatrixSpace`` or a basis for
23 a space of matrices. This function is needed because SageMath does
24 not know that matrix spaces are vector spaces, and therefore
25 cannot perform common operations with them -- like computing the
26 basis representation of an element.
28 Moreover, the ability to pass in a basis (rather than a
29 ``MatrixSpace``) is needed because SageMath has no way to express
30 that e.g. a (sub)space of symmetric matrices is itself a
35 - ``M`` -- Either a ``MatrixSpace``, or a list of matrices that form
36 a basis for a matrix space.
40 A pair of isometries ``(phi, phi_inv)``.
42 If the matrix space associated with `M` has dimension `n`, then
43 ``phi`` will map its elements to vectors of length `n` over the
44 same base ring. The inverse map ``phi_inv`` reverses that
49 sage: from mjo.matrix_vector import basis_representation
53 This function computes the correct coordinate representations (of
54 length 3) for a basis of the space of two-by-two symmetric
55 matrices, the the inverse does indeed invert the process::
57 sage: E11 = matrix(QQbar,[ [1,0],
59 sage: E12 = matrix(QQbar,[ [0, 1/sqrt(2)],
60 ....: [1/sqrt(2), 0] ])
61 sage: E22 = matrix(QQbar,[ [0,0],
63 sage: basis = [E11, E12, E22]
64 sage: phi, phi_inv = basis_representation(basis)
65 sage: phi(E11); phi(E12); phi(E22)
69 sage: phi_inv(phi(E11)) == E11
71 sage: phi_inv(phi(E12)) == E12
73 sage: phi_inv(phi(E22)) == E22
76 MatrixSpace arguments work too::
78 sage: M = MatrixSpace(QQ,2)
79 sage: phi, phi_inv = basis_representation(M)
80 sage: X = matrix(QQ, [ [1,2],
84 sage: phi_inv(phi(X)) == X
89 The inverse is generally an inverse::
91 sage: set_random_seed()
92 sage: n = ZZ.random_element(10)
93 sage: M = MatrixSpace(QQ,n)
94 sage: X = M.random_element()
95 sage: (phi, phi_inv) = basis_representation(M)
96 sage: phi_inv(phi(X)) == X
100 if is_MatrixSpace(M
):
102 basis
= list(M
.basis())
104 basis_space
= M
[0].matrix_space()
109 The isometry sending ``X`` to its representation as a long vector.
111 if X
not in basis_space
:
112 raise ValueError("X does not live in the domain of phi")
114 V
= VectorSpace(basis_space
.base_ring(), X
.nrows()*X
.ncols())
115 W
= V
.span_of_basis( _mat2vec(s
) for s
in basis
)
116 return W
.coordinate_vector(_mat2vec(X
))
120 The isometry sending the long vector `Y` to an element of either
121 `M` or the span of `M` (depending on whether or not ``M``
122 is a ``MatrixSpace`` or a basis).
124 return basis_space
.linear_combination( zip(Y
,basis
) )
126 return (phi
, phi_inv
)
130 def matrix_of_transformation(T
, V
):
132 Compute the matrix of a linear transformation ``T``, `$T : V
133 \rightarrow V$` with domain/range ``V``. This essentially uses the
134 Riesz representation theorem to represent the entries of the matrix
135 of ``T`` in terms of inner products.
139 - ``T`` -- The linear transformation whose matrix we should
140 compute. This should be a callable function that
141 takes as its single argument an element of ``V``.
143 - ``V`` -- The vector or matrix space on which ``T`` is defined.
147 If the dimension of ``V`` is `$n$`, we return an `$n \times n$`
148 matrix that represents ``T`` with respect to the standard basis of
153 sage: from mjo.matrix_vector import (basis_representation,
154 ....: matrix_of_transformation)
158 The matrix of a transformation on a simple vector space should be
159 the expected matrix::
161 sage: V = VectorSpace(QQ, 3)
165 sage: matrix_of_transformation(f, V)
170 A more complicated example confirms that we get a matrix consistent
171 with our ``matrix_to_vector`` function::
173 sage: M = MatrixSpace(QQ,3,3)
174 sage: Q = M([[0,1,0],[1,0,0],[0,0,1]])
176 ....: return Q*x*Q.inverse()
178 sage: F = matrix_of_transformation(f, M)
189 sage: phi, phi_inv = isomorphism(M)
190 sage: X = M([[1,2,3],[4,5,6],[7,8,9]])
192 (5, 4, 6, 2, 1, 3, 8, 7, 9)
194 (5, 4, 6, 2, 1, 3, 8, 7, 9)
195 sage: F*phi(X) == phi(f(X))
202 def inner_product(v
, w
):
203 # An inner product function that works for both matrices and
205 if callable(getattr(v
, 'inner_product', None)):
206 return v
.inner_product(w
)
207 elif callable(getattr(v
, 'matrix_space', None)):
208 # V must be a matrix space?
209 return (v
*w
.transpose()).trace()
211 raise ValueError('inner_product only works on vectors and matrices')
214 # A "call" that works for both matrices and functions.
215 if callable(getattr(L
, 'matrix_space', None)):
216 # L is a matrix, and we need to use "multiply" to call it.
219 # If L isn't a matrix, try this. It works for python
220 # functions at least.
226 entry
= inner_product(apply(T
,B
[i
]), B
[j
])
227 entries
.append(entry
)
229 # Construct the matrix space in which our return value will lie.
230 W
= MatrixSpace(V
.base_ring(), n
, n
)
232 # And make a matrix out of our list of entries.