This repository has been archived by the owner on Jan 30, 2023. It is now read-only.
/
echelon_matrix.pyx
147 lines (122 loc) · 4.46 KB
/
echelon_matrix.pyx
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
r"""
Echelon matrices over finite fields.
"""
#*****************************************************************************
# Copyright (C) 2014 Vincent Delecroix <20100.delecroix@gmail.com>
#
# Distributed under the terms of the GNU General Public License (GPL)
# as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# http://www.gnu.org/licenses/
#*****************************************************************************
from __future__ import print_function
from sage.matrix.matrix0 cimport Matrix
def reduced_echelon_matrix_iterator(K, k, n, bint sparse=False, bint copy=True, bint set_immutable=False):
r"""
An iterator over `(k,n)` reduced echelon matrices over the finite field `K`.
INPUT:
- ``K`` -- a finite field
- ``k`` -- number of rows (or the size of the subspace)
- ``n`` -- number of columns (or the dimension of the ambient space)
- ``sparse`` -- boolean (default is ``False``)
- ``copy`` -- boolean. If set to ``False`` then iterator yields the same matrix
over and over (but with different entries). Default is ``True`` which is
safer but might be slower.
- ``set_immutable`` -- boolean. If set to ``True`` then the output matrices
are immutable. This option automatically turns ``copy`` into ``True``.
EXAMPLES::
sage: from sage.matrix.echelon_matrix import reduced_echelon_matrix_iterator
sage: it = reduced_echelon_matrix_iterator(GF(2),2,3)
sage: for m in it:
....: print(m)
....: print(m.pivots())
....: print("*******")
[1 0 0]
[0 1 0]
(0, 1)
*******
[1 0 0]
[0 1 1]
(0, 1)
*******
[1 0 1]
[0 1 0]
(0, 1)
*******
[1 0 1]
[0 1 1]
(0, 1)
*******
[1 0 0]
[0 0 1]
(0, 2)
*******
[1 1 0]
[0 0 1]
(0, 2)
*******
[0 1 0]
[0 0 1]
(1, 2)
*******
TESTS:
Testing cardinalities::
sage: q = 71
sage: F = GF(q)
sage: len(list(reduced_echelon_matrix_iterator(F, 1, 3, copy=False))) == q**2+q+1
True
sage: len(list(reduced_echelon_matrix_iterator(F, 2, 3, copy=False))) == q**2+q+1
True
Testing options::
sage: it = reduced_echelon_matrix_iterator(GF(4,'z'), 2, 4, copy=False)
sage: next(it) is next(it)
True
sage: for a in it: pass
sage: it = reduced_echelon_matrix_iterator(GF(4,'z'), 2, 4, set_immutable=True)
sage: all(a.is_immutable() and a.echelon_form() == a for a in it)
True
"""
cdef Matrix m0,m,mm
cdef int i
n = int(n)
k = int(k)
if n < k:
raise NotImplementedError("echelon matrix with fewer rows than columns "
"i.e. not full rank) are not implemented")
from sage.matrix.matrix_space import MatrixSpace
from itertools import combinations,product
copy = copy or set_immutable
m0 = MatrixSpace(K,k,n,sparse=sparse)()
Klist = list(K)
K1 = K.one()
# First, we select which columns will be pivots:
# TODO: it would be much faster with a Gray code (only one pivot changing at
# a time) and would avoid the m0.__copy__()
for pivots in combinations(range(n),k):
m = m0.__copy__()
free_positions = []
for i in range(k):
m[i,pivots[i]] = K1
for j in range(pivots[i]+1,n):
if j not in pivots:
free_positions.append((i,j))
# Next, we fill in those entries that are not
# determined by the echelon form alone:
# TODO: it would be much faster with a Gray code (only one entry
# changing at a time)
num_free_pos = len(free_positions)
for v in product(Klist, repeat=num_free_pos):
for i in range(num_free_pos):
m[free_positions[i]] = v[i]
if copy:
mm = m.__copy__()
mm.cache('pivots',pivots)
mm.cache('rank',k)
mm.cache('in_echelon_form',True)
if set_immutable:
mm.set_immutable()
yield mm
else:
yield m
del v # hack: Python itertools reuses the tuple if nobody else uses it
del pivots # hack: Python itertools reuses the tuple if nobody else uses it