Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/matrix/matrix_misc.py
4045 views
1
"""
2
Miscellaneous matrix functions
3
4
"""
5
6
#*****************************************************************************
7
# Copyright (C) 2008 William Stein <[email protected]>
8
#
9
# Distributed under the terms of the GNU General Public License (GPL)
10
#
11
# This code is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
# General Public License for more details.
15
#
16
# The full text of the GPL is available at:
17
#
18
# http://www.gnu.org/licenses/
19
#*****************************************************************************
20
21
def row_iterator(A):
22
for i in xrange(A.nrows()):
23
yield A.row(i)
24
25
def weak_popov_form(M,ascend=True):
26
"""
27
This function computes a weak Popov form of a matrix over a rational
28
function field `k(x)`, for `k` a field.
29
30
INPUT:
31
32
- `M` - matrix
33
34
- `ascend` - if True, rows of output matrix `W` are sorted so
35
degree (= the maximum of the degrees of the elements in
36
the row) increases monotonically, and otherwise degrees decrease.
37
38
OUTPUT:
39
40
A 3-tuple `(W,N,d)` consisting of two matrices over `k(x)` and a list
41
of integers:
42
43
1. `W` - matrix giving a weak the Popov form of M
44
2. `N` - matrix representing row operations used to transform
45
`M` to `W`
46
3. `d` - degree of respective columns of W; the degree of a column is
47
the maximum of the degree of its elements
48
49
`N` is invertible over `k(x)`. These matrices satisfy the relation
50
`N*M = W`.
51
52
EXAMPLES:
53
54
The routine expects matrices over the rational function field, but
55
other examples below show how one can provide matrices over the ring
56
of polynomials (whose quotient field is the rational function field).
57
58
::
59
60
sage: R.<t> = GF(3)['t']
61
sage: K = FractionField(R)
62
sage: import sage.matrix.matrix_misc
63
sage: sage.matrix.matrix_misc.weak_popov_form(matrix([[(t-1)^2/t],[(t-1)]]))
64
(
65
[ 0] [ t 2*t + 1]
66
[(2*t + 1)/t], [ 1 2], [-Infinity, 0]
67
)
68
69
NOTES:
70
71
See docstring for weak_popov_form method of matrices for
72
more information.
73
"""
74
75
# determine whether M has polynomial or rational function coefficients
76
R0 = M.base_ring()
77
78
from sage.rings.ring import is_Field
79
80
#Compute the base polynomial ring
81
82
if is_Field(R0):
83
R = R0.base()
84
else:
85
R = R0
86
from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
87
if not is_PolynomialRing(R):
88
raise TypeError("the coefficients of M must lie in a univariate polynomial ring")
89
90
t = R.gen()
91
92
# calculate least-common denominator of matrix entries and clear
93
# denominators. The result lies in R
94
from sage.rings.arith import lcm
95
from sage.matrix.constructor import matrix
96
from sage.misc.functional import numerator
97
if is_Field(R0):
98
den = lcm([a.denominator() for a in M.list()])
99
num = matrix([(lambda x : map(numerator, x))(v) for v in map(list,(M*den).rows())])
100
else:
101
# No need to clear denominators
102
den = R.one_element()
103
num = M
104
105
r = [list(v) for v in num.rows()]
106
107
N = matrix(num.nrows(), num.nrows(), R(1)).rows()
108
109
from sage.rings.infinity import Infinity
110
if M.is_zero():
111
return (M, matrix(N), [-Infinity for i in range(num.nrows())])
112
113
rank = 0
114
num_zero = 0
115
while rank != len(r) - num_zero:
116
# construct matrix of leading coefficients
117
v = []
118
for w in map(list, r):
119
# calculate degree of row (= max of degree of entries)
120
d = max([e.numerator().degree() for e in w])
121
122
# extract leading coefficients from current row
123
x = []
124
for y in w:
125
if y.degree() >= d and d >= 0: x.append(y.coeffs()[d])
126
else: x.append(0)
127
v.append(x)
128
l = matrix(v)
129
130
# count number of zero rows in leading coefficient matrix
131
# because they do *not* contribute interesting relations
132
num_zero = 0
133
for v in l.rows():
134
is_zero = 1
135
for w in v:
136
if w != 0:
137
is_zero = 0
138
if is_zero == 1:
139
num_zero += 1
140
141
# find non-trivial relations among the columns of the
142
# leading coefficient matrix
143
kern = l.kernel().basis()
144
rank = num.nrows() - len(kern)
145
146
# do a row operation if there's a non-trivial relation
147
if not rank == len(r) - num_zero:
148
for rel in kern:
149
# find the row of num involved in the relation and of
150
# maximal degree
151
indices = []
152
degrees = []
153
for i in range(len(rel)):
154
if rel[i] != 0:
155
indices.append(i)
156
degrees.append(max([e.degree() for e in r[i]]))
157
158
# find maximum degree among rows involved in relation
159
max_deg = max(degrees)
160
161
# check if relation involves non-zero rows
162
if max_deg != -1:
163
i = degrees.index(max_deg)
164
rel /= rel[indices[i]]
165
166
for j in range(len(indices)):
167
if j != i:
168
# do row operation and record it
169
v = []
170
for k in range(len(r[indices[i]])):
171
v.append(r[indices[i]][k] + rel[indices[j]] * t**(max_deg-degrees[j]) * r[indices[j]][k])
172
r[indices[i]] = v
173
174
v = []
175
for k in range(len(N[indices[i]])):
176
v.append(N[indices[i]][k] + rel[indices[j]] * t**(max_deg-degrees[j]) * N[indices[j]][k])
177
N[indices[i]] = v
178
179
# remaining relations (if any) are no longer valid,
180
# so continue onto next step of algorithm
181
break
182
183
# sort the rows in order of degree
184
d = []
185
from sage.rings.all import infinity
186
for i in range(len(r)):
187
d.append(max([e.degree() for e in r[i]]))
188
if d[i] < 0:
189
d[i] = -infinity
190
else:
191
d[i] -= den.degree()
192
193
for i in range(len(r)):
194
for j in range(i+1,len(r)):
195
if (ascend and d[i] > d[j]) or (not ascend and d[i] < d[j]):
196
(r[i], r[j]) = (r[j], r[i])
197
(d[i], d[j]) = (d[j], d[i])
198
(N[i], N[j]) = (N[j], N[i])
199
200
# return reduced matrix and operations matrix
201
return (matrix(r)/den, matrix(N), d)
202
203