Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/modules/free_quadratic_module.py
4056 views
1
r"""
2
Free quadratic modules
3
4
Sage supports computation with free quadratic modules over an arbitrary
5
commutative ring. Nontrivial functionality is available over $\Z$ and
6
fields. All free modules over an integral domain are equipped with an
7
embedding in an ambient vector space and an inner product, which you
8
can specify and change.
9
10
Create the free module of rank $n$ over an arbitrary commutative ring $R$
11
using the command \code{FreeModule(R,n)} with a given inner_product_matrix.
12
13
The following example illustrates the creation of both a vector spaces
14
and a free module over the integers and a submodule of it. Use the functions
15
\code{FreeModule}, \code{span} and member functions of free modules
16
to create free modules. \emph{Do not use the FreeModule\_xxx constructors
17
directly.}
18
19
EXAMPLES:
20
sage: M = Matrix(QQ,[[2,1,0],[1,2,1],[0,1,2]])
21
sage: V = VectorSpace(QQ,3,inner_product_matrix=M)
22
sage: type(V)
23
<class 'sage.modules.free_quadratic_module.FreeQuadraticModule_ambient_field_with_category'>
24
sage: V.inner_product_matrix()
25
[2 1 0]
26
[1 2 1]
27
[0 1 2]
28
sage: W = V.subspace([[1,2,7], [1,1,0]])
29
sage: type(W)
30
<class 'sage.modules.free_quadratic_module.FreeQuadraticModule_submodule_field_with_category'>
31
sage: W
32
Quadratic space of degree 3 and dimension 2 over Rational Field
33
Basis matrix:
34
[ 1 0 -7]
35
[ 0 1 7]
36
Inner product matrix:
37
[2 1 0]
38
[1 2 1]
39
[0 1 2]
40
sage: W.gram_matrix()
41
[ 100 -104]
42
[-104 114]
43
44
TESTS:
45
sage: M = Matrix(QQ,[[2,1,0],[1,2,1],[0,1,2]])
46
sage: V = VectorSpace(QQ,3,inner_product_matrix = M)
47
sage: V == loads(dumps(V))
48
True
49
sage: W = QuadraticSpace(QQ,3,M)
50
sage: W == V
51
True
52
53
AUTHORS:
54
--David Kohel (2008-06): First created (based on free_module.py)
55
"""
56
57
#*****************************************************************************
58
#
59
# Copyright (C) 2008 David Kohel <[email protected]>
60
#
61
# Distributed under the terms of the GNU General Public License (GPL)
62
#
63
# http://www.gnu.org/licenses/
64
#
65
# All rights granted to distribute under the GPL, version 2,
66
# or (at your option) any later version of the license.
67
#
68
#*****************************************************************************
69
70
# Python imports
71
import weakref
72
73
# Sage imports
74
75
76
import sage.matrix.matrix_space
77
78
import sage.misc.latex as latex
79
80
import sage.rings.principal_ideal_domain as principal_ideal_domain
81
import sage.rings.field as field
82
import sage.rings.integral_domain as integral_domain
83
import sage.rings.integer
84
import sage.structure.parent_gens as gens
85
86
87
import free_module
88
89
###############################################################################
90
#
91
# Constructor functions
92
#
93
###############################################################################
94
_cache = {}
95
96
def FreeQuadraticModule(
97
base_ring, rank, inner_product_matrix, sparse=False, inner_product_ring=None):
98
r"""
99
Create the free quadratic module over the given commutative ring of the given rank.
100
101
INPUT:
102
base_ring -- a commutative ring
103
rank -- a nonnegative integer
104
inner_product_matrix -- the inner product matrix
105
sparse -- bool; (default False)
106
inner_product_ring -- the inner product codomain ring; (default None)
107
108
OUTPUT:
109
A free quadratic module (with given inner product matrix).
110
111
\note{In \sage it is the case that there is only one dense and one
112
sparse free ambient quadratic module of rank $n$ over $R$ and given
113
inner product matrix.}
114
115
116
EXAMPLES:
117
118
sage: M1 = FreeQuadraticModule(ZZ,2,inner_product_matrix=1)
119
sage: M1 is FreeModule(ZZ,2,inner_product_matrix=1)
120
True
121
sage: M1.inner_product_matrix()
122
[1 0]
123
[0 1]
124
sage: M1 == ZZ^2
125
True
126
sage: M1 is ZZ^2
127
False
128
sage: M2 = FreeQuadraticModule(ZZ,2,inner_product_matrix=[1,2,3,4])
129
sage: M2 is FreeQuadraticModule(ZZ,2,inner_product_matrix=[1,2,3,4])
130
True
131
sage: M2.inner_product_matrix()
132
[1 2]
133
[3 4]
134
sage: M3 = FreeModule(ZZ,2,inner_product_matrix=[[1,2],[3,4]])
135
sage: M3 is M2
136
True
137
"""
138
global _cache
139
rank = int(rank)
140
141
if inner_product_matrix is None:
142
raise ValueError, "An inner_product_matrix must be specified."
143
144
# In order to use coercion into the inner_product_ring we need to pass
145
# this ring into the vector classes.
146
if inner_product_ring is not None:
147
raise NotImplementedError, "An inner_product_ring can not currently be defined."
148
149
inner_product_matrix = sage.matrix.matrix_space.MatrixSpace(base_ring, rank)(inner_product_matrix)
150
inner_product_matrix.set_immutable()
151
152
key = (base_ring, rank, inner_product_matrix, sparse)
153
154
if _cache.has_key(key):
155
M = _cache[key]()
156
if not (M is None):
157
return M
158
159
if not base_ring.is_commutative():
160
raise TypeError, "base_ring must be a commutative ring"
161
162
#elif not sparse and isinstance(base_ring,sage.rings.real_double.RealDoubleField_class):
163
# M = RealDoubleQuadraticSpace_class(rank, inner_product_matrix=inner_product_matrix, sparse=False)
164
165
#elif not sparse and isinstance(base_ring,sage.rings.complex_double.ComplexDoubleField_class):
166
# M = ComplexDoubleQuadraticSpace_class(rank, inner_product_matrix=inner_product_matrix, sparse=False)
167
168
elif base_ring.is_field():
169
M = FreeQuadraticModule_ambient_field(
170
base_ring, rank, sparse=sparse, inner_product_matrix=inner_product_matrix)
171
172
elif isinstance(base_ring, principal_ideal_domain.PrincipalIdealDomain):
173
M = FreeQuadraticModule_ambient_pid(
174
base_ring, rank, sparse=sparse, inner_product_matrix=inner_product_matrix)
175
176
elif isinstance(base_ring, integral_domain.IntegralDomain) or base_ring.is_integral_domain():
177
M = FreeQuadraticModule_ambient_domain(
178
base_ring, rank, sparse=sparse, inner_product_matrix=inner_product_matrix)
179
else:
180
M = FreeQuadraticModule_ambient(
181
base_ring, rank, sparse=sparse, inner_product_matrix=inner_product_matrix)
182
183
_cache[key] = weakref.ref(M)
184
return M
185
186
def QuadraticSpace(K, dimension, inner_product_matrix, sparse=False):
187
"""
188
EXAMPLES:
189
The base can be complicated, as long as it is a field.
190
sage: F.<x> = FractionField(PolynomialRing(ZZ,'x'))
191
sage: D = diagonal_matrix([x,x-1,x+1])
192
sage: V = QuadraticSpace(F,3,D)
193
sage: V
194
Ambient quadratic space of dimension 3 over Fraction Field of Univariate Polynomial Ring in x over Integer Ring
195
Inner product matrix:
196
[ x 0 0]
197
[ 0 x - 1 0]
198
[ 0 0 x + 1]
199
sage: V.basis()
200
[
201
(1, 0, 0),
202
(0, 1, 0),
203
(0, 0, 1)
204
]
205
206
The base must be a field or a \code{TypeError} is raised.
207
208
sage: QuadraticSpace(ZZ,5,identity_matrix(ZZ,2))
209
Traceback (most recent call last):
210
...
211
TypeError: Argument K (= Integer Ring) must be a field.
212
"""
213
if not K.is_field():
214
raise TypeError, "Argument K (= %s) must be a field." % K
215
if not sparse in (True,False):
216
raise TypeError, "Argument sparse (= %s) must be a boolean."%sparse
217
return FreeQuadraticModule(K, rank=dimension, inner_product_matrix=inner_product_matrix, sparse=sparse)
218
219
InnerProductSpace = QuadraticSpace
220
221
###############################################################################
222
#
223
# Base class for all free modules
224
#
225
###############################################################################
226
227
def is_FreeQuadraticModule(M):
228
"""
229
Returns True if M is a free quadratic module.
230
231
EXAMPLES:
232
sage: from sage.modules.free_quadratic_module import is_FreeQuadraticModule
233
sage: U = FreeModule(QQ,3)
234
sage: is_FreeQuadraticModule(U)
235
False
236
sage: V = FreeModule(QQ,3,inner_product_matrix=diagonal_matrix([1,1,1]))
237
sage: is_FreeQuadraticModule(V)
238
True
239
sage: W = FreeModule(QQ,3,inner_product_matrix=diagonal_matrix([2,3,3]))
240
sage: is_FreeQuadraticModule(W)
241
True
242
"""
243
return isinstance(M, FreeQuadraticModule_generic)
244
245
class FreeQuadraticModule_generic(free_module.FreeModule_generic):
246
"""
247
Base class for all free quadratic modules.
248
"""
249
def __init__(self, base_ring, rank, degree, inner_product_matrix, sparse=False):
250
"""
251
Create the free module of given rank over the given base_ring.
252
253
INPUT:
254
base_ring -- a commutative ring
255
rank -- a non-negative integer
256
257
EXAMPLES:
258
sage: R = PolynomialRing(QQ,3,'x')
259
sage: FreeModule(R,3,inner_product_matrix=diagonal_matrix(list(R.gens())))
260
Ambient free quadratic module of rank 3 over the integral domain Multivariate Polynomial Ring in x0, x1, x2 over Rational Field
261
Inner product matrix:
262
[x0 0 0]
263
[ 0 x1 0]
264
[ 0 0 x2]
265
"""
266
free_module.FreeModule_generic.__init__(
267
self, base_ring=base_ring, rank=rank, degree=degree, sparse=sparse)
268
self._inner_product_matrix=inner_product_matrix
269
270
def _dense_module(self):
271
"""
272
Creates a dense module with the same defining data as self.
273
274
N.B. This function is for internal use only! See dense_module for use.
275
276
EXAMPLES:
277
sage: A = diagonal_matrix([1,2,2])
278
sage: M = FreeModule(Integers(8),3,inner_product_matrix=A)
279
sage: S = FreeModule(Integers(8),3,inner_product_matrix=A,sparse=True)
280
sage: M is S._dense_module()
281
True
282
"""
283
A = self.ambient_module().dense_module()
284
return A.span(self.basis())
285
286
def _sparse_module(self):
287
"""
288
Creates a sparse module with the same defining data as self.
289
290
N.B. This function is for internal use only! See sparse_module for use.
291
292
EXAMPLES:
293
sage: A = diagonal_matrix([1,2,2])
294
sage: M = FreeModule(Integers(8),3,inner_product_matrix=A)
295
sage: S = FreeModule(Integers(8),3,inner_product_matrix=A,sparse=True)
296
sage: M._sparse_module() is S
297
True
298
"""
299
A = self.ambient_module().sparse_module()
300
return A.span(self.basis())
301
302
def ambient_module(self):
303
"""
304
Return the ambient module associated to this module.
305
306
EXAMPLES:
307
sage: R.<x,y> = QQ[]
308
sage: M = FreeModule(R,2)
309
sage: M.ambient_module()
310
Ambient free module of rank 2 over the integral domain Multivariate Polynomial Ring in x, y over Rational Field
311
312
sage: V = FreeModule(QQ, 4).span([[1,2,3,4], [1,0,0,0]]); V
313
Vector space of degree 4 and dimension 2 over Rational Field
314
Basis matrix:
315
[ 1 0 0 0]
316
[ 0 1 3/2 2]
317
sage: V.ambient_module()
318
Vector space of dimension 4 over Rational Field
319
"""
320
return FreeQuadraticModule(self.base_ring(), self.degree(), self.inner_product_matrix())
321
322
def determinant(self):
323
"""
324
Return the determinant of this free module.
325
326
EXAMPLES:
327
sage: M = FreeModule(ZZ, 3, inner_product_matrix=1)
328
sage: M.determinant()
329
1
330
sage: N = M.span([[1,2,3]])
331
sage: N.determinant()
332
14
333
sage: P = M.span([[1,2,3], [1,1,1]])
334
sage: P.determinant()
335
6
336
"""
337
return self.gram_matrix().determinant()
338
339
def discriminant(self):
340
"""
341
Return the discriminant of this free module, defined to be (-1)^r
342
of the determinant, where r = n/2 (n even) or (n-1)/2 (n odd) for
343
a module of rank n.
344
345
EXAMPLES:
346
sage: M = FreeModule(ZZ, 3)
347
sage: M.discriminant()
348
1
349
sage: N = M.span([[1,2,3]])
350
sage: N.discriminant()
351
14
352
sage: P = M.span([[1,2,3], [1,1,1]])
353
sage: P.discriminant()
354
6
355
"""
356
n = self.rank()
357
if n%2 == 0:
358
r = n//2
359
else:
360
r = (n-1)//2
361
return (-1)^r*self.gram_matrix().determinant()
362
363
def gram_matrix(self):
364
"""
365
Return the gram matrix associated to this free module, defined to be
366
G = B*A*B.transpose(), where A is the inner product matrix (induced from
367
the ambient space), and B the basis matrix.
368
369
EXAMPLES:
370
sage: V = VectorSpace(QQ,4)
371
sage: u = V([1/2,1/2,1/2,1/2])
372
sage: v = V([0,1,1,0])
373
sage: w = V([0,0,1,1])
374
sage: M = span([u,v,w], ZZ)
375
sage: M.inner_product_matrix() == V.inner_product_matrix()
376
True
377
sage: L = M.submodule_with_basis([u,v,w])
378
sage: L.inner_product_matrix() == M.inner_product_matrix()
379
True
380
sage: L.gram_matrix()
381
[1 1 1]
382
[1 2 1]
383
[1 1 2]
384
385
"""
386
if self.is_ambient():
387
return self.inner_product_matrix()
388
else:
389
if self._gram_matrix is None:
390
A = self.inner_product_matrix()
391
B = self.basis_matrix()
392
self._gram_matrix = B*A*B.transpose()
393
return self._gram_matrix
394
395
def inner_product_matrix(self):
396
"""
397
Return the inner product matrix associated to this module. By definition this
398
is the inner product matrix of the ambient space, hence may be of degree greater
399
than the rank of the module.
400
401
N.B. The inner product does not have to be symmetric (see examples).
402
403
TODO: Differentiate the image ring of the inner product from the base ring of
404
the module and/or ambient space. E.g. On an integral module over ZZ the inner
405
product pairing could naturally take values in ZZ, QQ, RR, or CC.
406
407
EXAMPLES:
408
sage: M = FreeModule(ZZ, 3)
409
sage: M.inner_product_matrix()
410
[1 0 0]
411
[0 1 0]
412
[0 0 1]
413
414
The inner product does not have to be symmetric or definite.
415
416
sage: N = FreeModule(ZZ,2,inner_product_matrix=[[1,-1],[2,5]])
417
sage: N.inner_product_matrix()
418
[ 1 -1]
419
[ 2 5]
420
sage: u, v = N.basis()
421
sage: u.inner_product(v)
422
-1
423
sage: v.inner_product(u)
424
2
425
426
The inner product matrix is defined with respect to the ambient space.
427
428
sage: V = QQ^3
429
sage: u = V([1/2,1,1])
430
sage: v = V([1,1,1/2])
431
sage: M = span([u,v], ZZ)
432
sage: M.inner_product_matrix()
433
[1 0 0]
434
[0 1 0]
435
[0 0 1]
436
sage: M.inner_product_matrix() == V.inner_product_matrix()
437
True
438
sage: M.gram_matrix()
439
[ 1/2 -3/4]
440
[-3/4 13/4]
441
442
"""
443
return self._inner_product_matrix
444
445
def _inner_product_is_dot_product(self):
446
"""
447
Return whether or not the inner product on this module is induced by
448
the dot product on the ambient vector space. This is used internally
449
by the inner_product function for optimization.
450
451
EXAMPLES:
452
sage: FreeModule(ZZ, 3)._inner_product_is_dot_product()
453
True
454
sage: FreeModule(ZZ, 3, inner_product_matrix=1)._inner_product_is_dot_product()
455
True
456
sage: FreeModule(ZZ, 2, inner_product_matrix=[1,0,-1,0])._inner_product_is_dot_product()
457
False
458
459
sage: M = FreeModule(QQ, 3)
460
sage: M2 = M.span([[1,2,3]])
461
sage: M2._inner_product_is_dot_product()
462
True
463
"""
464
return self.inner_product_matrix() == 1
465
466
467
def _inner_product_is_diagonal(self):
468
"""
469
Return whether or not the inner product on this module is induced by
470
the dot product on the ambient vector space. This is used internally
471
by the inner_product function for optimization.
472
473
N.B. The FreeModule classes have the identity inner product matrix,
474
while FreeQuadraticModules must have an inner_product_matrix, although
475
it can be diagonal.
476
477
EXAMPLES:
478
sage: M0 = FreeModule(ZZ, 3, inner_product_matrix=1)
479
sage: M0._inner_product_is_diagonal()
480
True
481
sage: D = diagonal_matrix([3,5,7])
482
sage: M1 = FreeModule(ZZ, 3, inner_product_matrix=D)
483
sage: M1._inner_product_is_diagonal()
484
True
485
sage: A = Matrix([[2,1,0],[1,2,1],[0,1,2]])
486
sage: M2 = FreeModule(ZZ, 3, inner_product_matrix=A)
487
sage: M2._inner_product_is_diagonal()
488
False
489
sage: M3 = FreeModule(ZZ, 2, inner_product_matrix=[1,0,-1,0])
490
sage: M3._inner_product_is_diagonal()
491
False
492
493
TODO: Actually use the diagonal form of the inner product.
494
"""
495
A = self.inner_product_matrix()
496
D = sage.matrix.constructor.diagonal_matrix([ A[i,i] for i in range(A.nrows()) ])
497
return A == D
498
499
class FreeQuadraticModule_generic_pid(
500
free_module.FreeModule_generic_pid, FreeQuadraticModule_generic):
501
"""
502
Class of all free modules over a PID.
503
"""
504
def __init__(self, base_ring, rank, degree, inner_product_matrix, sparse=False):
505
"""
506
Create a free module over a PID.
507
508
EXAMPLES:
509
sage: FreeModule(ZZ, 2, inner_product_matrix=Matrix([[2,1],[1,2]]))
510
Ambient free quadratic module of rank 2 over the principal ideal domain Integer Ring
511
Inner product matrix:
512
[2 1]
513
[1 2]
514
"""
515
free_module.FreeModule_generic_pid.__init__(
516
self, base_ring=base_ring, rank=rank, degree=degree, sparse=sparse)
517
#self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix
518
self._inner_product_matrix = inner_product_matrix
519
520
def span(self, gens, check=True, already_echelonized=False):
521
"""
522
Return the R-span of the given list of gens, where R
523
is the base ring of self. Note that this span need not
524
be a submodule of self, nor even of the ambient space.
525
It must, however, be contained in the ambient vector space, i.e.,
526
the ambient space tensored with the fraction field of R.
527
528
EXAMPLES:
529
sage: V = FreeModule(ZZ,3)
530
sage: W = V.submodule([V.gen(0)])
531
sage: W.span([V.gen(1)])
532
Free module of degree 3 and rank 1 over Integer Ring
533
Echelon basis matrix:
534
[0 1 0]
535
sage: W.submodule([V.gen(1)])
536
Traceback (most recent call last):
537
...
538
ArithmeticError: Argument gens (= [(0, 1, 0)]) does not generate a submodule of self.
539
"""
540
return FreeQuadraticModule_submodule_pid(
541
self.ambient_module(), gens, inner_product_matrix=self.inner_product_matrix(),
542
check=check, already_echelonized=already_echelonized)
543
544
def span_of_basis(self, basis, check=True, already_echelonized=False):
545
r"""
546
Return the free R-module with the given basis, where R
547
is the base ring of self. Note that this R-module need not
548
be a submodule of self, nor even of the ambient space. It
549
must, however, be contained in the ambient vector space, i.e.,
550
the ambient space tensored with the fraction field of R.
551
552
EXAMPLES:
553
sage: M = FreeModule(ZZ,3)
554
sage: W = M.span_of_basis([M([1,2,3])])
555
556
Next we create two free $\Z$-modules, neither of
557
which is a submodule of $W$.
558
sage: W.span_of_basis([M([2,4,0])])
559
Free module of degree 3 and rank 1 over Integer Ring
560
User basis matrix:
561
[2 4 0]
562
563
The following module isn't even in the ambient space.
564
sage: Q = QQ
565
sage: W.span_of_basis([ Q('1/5')*M([1,2,0]), Q('1/7')*M([1,1,0]) ])
566
Free module of degree 3 and rank 2 over Integer Ring
567
User basis matrix:
568
[1/5 2/5 0]
569
[1/7 1/7 0]
570
571
Of course the input basis vectors must be linearly independent.
572
573
sage: W.span_of_basis([ [1,2,0], [2,4,0] ])
574
Traceback (most recent call last):
575
...
576
ValueError: The given basis vectors must be linearly independent.
577
"""
578
return FreeQuadraticModule_submodule_with_basis_pid(
579
self.ambient_module(), basis=basis, inner_product_matrix=self.inner_product_matrix(),
580
check=check, already_echelonized=already_echelonized)
581
582
def zero_submodule(self):
583
"""
584
Return the zero submodule of this module.
585
586
EXAMPLES:
587
sage: V = FreeModule(ZZ,2)
588
sage: V.zero_submodule()
589
Free module of degree 2 and rank 0 over Integer Ring
590
Echelon basis matrix:
591
[]
592
"""
593
return FreeQuadraticModule_submodule_pid(
594
self.ambient_module(), [], self.inner_product_matrix(), check=False)
595
596
class FreeQuadraticModule_generic_field(
597
free_module.FreeModule_generic_field, FreeQuadraticModule_generic_pid):
598
"""
599
Base class for all free modules over fields.
600
"""
601
def __init__(self, base_field, dimension, degree, inner_product_matrix, sparse=False):
602
"""
603
Creates a vector space over a field.
604
605
EXAMPLES:
606
sage: FreeModule(QQ, 2, inner_product_matrix=[[2,1],[1,2]])
607
Ambient quadratic space of dimension 2 over Rational Field
608
Inner product matrix:
609
[2 1]
610
[1 2]
611
sage: FreeModule(FiniteField(2), 7, inner_product_matrix=1)
612
Ambient quadratic space of dimension 7 over Finite Field of size 2
613
Inner product matrix:
614
[1 0 0 0 0 0 0]
615
[0 1 0 0 0 0 0]
616
[0 0 1 0 0 0 0]
617
[0 0 0 1 0 0 0]
618
[0 0 0 0 1 0 0]
619
[0 0 0 0 0 1 0]
620
[0 0 0 0 0 0 1]
621
"""
622
if not isinstance(base_field, field.Field):
623
raise TypeError, "The base_field (=%s) must be a field" % base_field
624
free_module.FreeModule_generic_field.__init__(
625
self, base_field=base_field, dimension=dimension, degree=degree, sparse=sparse)
626
#self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix
627
self._inner_product_matrix = inner_product_matrix
628
629
def span(self, gens, check=True, already_echelonized=False):
630
"""
631
Return the K-span of the given list of gens, where K is the
632
base field of self. Note that this span is a subspace of the
633
ambient vector space, but need not be a subspace of self.
634
635
INPUT:
636
gens -- list of vectors
637
check -- bool (default: True): whether or not to coerce entries of gens
638
into base field
639
already_echelonized -- bool (default: False): set this if you know the gens
640
are already in echelon form
641
642
EXAMPLES:
643
sage: V = VectorSpace(GF(7), 3)
644
sage: W = V.subspace([[2,3,4]]); W
645
Vector space of degree 3 and dimension 1 over Finite Field of size 7
646
Basis matrix:
647
[1 5 2]
648
sage: W.span([[1,1,1]])
649
Vector space of degree 3 and dimension 1 over Finite Field of size 7
650
Basis matrix:
651
[1 1 1]
652
"""
653
if free_module.is_FreeModule(gens):
654
gens = gens.gens()
655
if not isinstance(gens, (list, tuple)):
656
raise TypeError, "gens (=%s) must be a list or tuple"%gens
657
658
return FreeQuadraticModule_submodule_field(
659
self.ambient_module(), gens,
660
inner_product_matrix=self.inner_product_matrix(),
661
check=check, already_echelonized=already_echelonized)
662
663
def span_of_basis(self, basis, check=True, already_echelonized=False):
664
r"""
665
Return the free K-module with the given basis, where K
666
is the base field of self. Note that this span is
667
a subspace of the ambient vector space, but need
668
not be a subspace of self.
669
670
INPUT:
671
basis -- list of vectors
672
check -- bool (default: True): whether or not to coerce entries of gens
673
into base field
674
already_echelonized -- bool (default: False): set this if you know the gens
675
are already in echelon form
676
677
EXAMPLES:
678
sage: V = VectorSpace(GF(7), 3)
679
sage: W = V.subspace([[2,3,4]]); W
680
Vector space of degree 3 and dimension 1 over Finite Field of size 7
681
Basis matrix:
682
[1 5 2]
683
sage: W.span_of_basis([[2,2,2], [3,3,0]])
684
Vector space of degree 3 and dimension 2 over Finite Field of size 7
685
User basis matrix:
686
[2 2 2]
687
[3 3 0]
688
689
The basis vectors must be linearly independent or an ArithmeticError exception
690
is raised.
691
sage: W.span_of_basis([[2,2,2], [3,3,3]])
692
Traceback (most recent call last):
693
...
694
ValueError: The given basis vectors must be linearly independent.
695
"""
696
return FreeQuadraticModule_submodule_with_basis_field(
697
self.ambient_module(), basis=basis,
698
inner_product_matrix=self.inner_product_matrix(),
699
check=check, already_echelonized=already_echelonized)
700
701
###############################################################################
702
#
703
# Generic ambient free modules, i.e., of the form R^n for some commutative ring R.
704
#
705
###############################################################################
706
707
class FreeQuadraticModule_ambient(
708
free_module.FreeModule_ambient, FreeQuadraticModule_generic):
709
"""
710
Ambient free module over a commutative ring.
711
"""
712
def __init__(self, base_ring, rank, inner_product_matrix, sparse=False):
713
"""
714
The free module of given rank over the given base_ring.
715
716
INPUT:
717
base_ring -- a commutative ring
718
rank -- a non-negative integer
719
720
EXAMPLES:
721
sage: FreeModule(ZZ, 4)
722
Ambient free module of rank 4 over the principal ideal domain Integer Ring
723
"""
724
free_module.FreeModule_ambient.__init__(self, base_ring=base_ring, rank=rank, sparse=sparse)
725
#self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix
726
self._inner_product_matrix = inner_product_matrix
727
728
def _repr_(self):
729
"""
730
The printing representation of self.
731
732
EXAMPLES:
733
sage: R = ZZ.quo(12)
734
sage: M = R^12
735
sage: print M
736
Ambient free module of rank 12 over Ring of integers modulo 12
737
sage: print M._repr_()
738
Ambient free module of rank 12 over Ring of integers modulo 12
739
740
The system representation can be overwritten, but leaves _repr_ unmodified.
741
742
sage: M.rename('M')
743
sage: print M
744
M
745
sage: print M._repr_()
746
Ambient free module of rank 12 over Ring of integers modulo 12
747
748
Sparse modules print this fact.
749
750
sage: N = FreeModule(R,12,sparse=True)
751
sage: print N
752
Ambient sparse free module of rank 12 over Ring of integers modulo 12
753
"""
754
if self.is_sparse():
755
return "Ambient sparse free quadratic module of rank %s over %s\n" % ( self.rank(), self.base_ring() ) + \
756
"Inner product matrix:\n%s" % self.inner_product_matrix()
757
else:
758
return "Ambient free quadratic module of rank %s over %s\n" % ( self.rank(), self.base_ring() ) + \
759
"Inner product matrix:\n%s" % self.inner_product_matrix()
760
761
def __cmp__(self, other):
762
"""
763
Compare self and other.
764
765
Modules are ordered by their ambient spaces, then by
766
dimension, then in order by their echelon matrices.
767
768
EXAMPLES:
769
We compare rank three free modules over the integers and rationals:
770
sage: QQ^3 < CC^3
771
True
772
sage: CC^3 < QQ^3
773
False
774
sage: CC^3 > QQ^3
775
True
776
sage: Q = QQ; Z = ZZ
777
sage: Q^3 > Z^3
778
True
779
sage: Q^3 < Z^3
780
False
781
sage: Z^3 < Q^3
782
True
783
sage: Z^3 > Q^3
784
False
785
sage: Q^3 == Z^3
786
False
787
sage: Q^3 == Q^3
788
True
789
790
sage: V = span([[1,2,3], [5,6,7], [8,9,10]], QQ)
791
sage: V
792
Vector space of degree 3 and dimension 2 over Rational Field
793
Basis matrix:
794
[ 1 0 -1]
795
[ 0 1 2]
796
sage: A = QQ^3
797
sage: V < A
798
True
799
sage: A < V
800
False
801
"""
802
if self is other:
803
return 0
804
if not isinstance(other, free_module.FreeModule_generic):
805
return cmp(type(self), type(other))
806
if isinstance(other, free_module.FreeModule_ambient):
807
c = cmp(self.rank(), other.rank())
808
if c: return c
809
c = cmp(self.base_ring(), other.base_ring())
810
if not c:
811
return c
812
try:
813
if self.base_ring().is_subring(other.base_ring()):
814
return -1
815
elif other.base_ring().is_subring(self.base_ring()):
816
return 1
817
except NotImplementedError:
818
pass
819
return c
820
else: # now other is not ambient; it knows how to do the comparison.
821
return -other.__cmp__(self)
822
823
def _latex_(self):
824
r"""
825
Return a latex representation of this ambient free quadratic module.
826
827
EXAMPLES:
828
sage: latex(QQ^3) # indirect doctest
829
\Bold{Q}^{3}
830
831
sage: A = GF(5)^20; latex(A)
832
\Bold{F}_{5}^{20}
833
834
sage: A = PolynomialRing(QQ,3,'x')^20; latex(A)
835
(\Bold{Q}[x_{0}, x_{1}, x_{2}])^{20}
836
837
sage: V = QuadraticSpace(QQ,3,inner_product_matrix=[[2,1,0],[1,4,1],[0,1,8]])
838
sage: latex(V)
839
None
840
"""
841
# How do we want to represent this object?
842
NotImplementedError
843
844
def _dense_module(self):
845
"""
846
Creates a dense module with the same defining data as self.
847
848
N.B. This function is for internal use only! See dense_module for use.
849
850
EXAMPLES:
851
sage: A = diagonal_matrix([1,2,2])
852
sage: M = FreeModule(Integers(8),3,inner_product_matrix=A)
853
sage: S = FreeModule(Integers(8),3,inner_product_matrix=A,sparse=True)
854
sage: M is S._dense_module()
855
True
856
"""
857
return FreeQuadraticModule(base_ring=self.base_ring(), rank = self.rank(),
858
inner_product_matrix = self.inner_product_matrix(), sparse=False)
859
860
def _sparse_module(self):
861
"""
862
Creates a sparse module with the same defining data as self.
863
864
N.B. This function is for internal use only! See sparse_module for use.
865
866
EXAMPLES:
867
sage: A = diagonal_matrix([1,2,2])
868
sage: M = FreeModule(Integers(8),3,inner_product_matrix=A)
869
sage: S = FreeModule(Integers(8),3,inner_product_matrix=A,sparse=True)
870
sage: M._sparse_module() is S
871
True
872
"""
873
return FreeQuadraticModule(base_ring = self.base_ring(), rank = self.rank(),
874
inner_product_matrix = self.inner_product_matrix(), sparse=True)
875
876
###############################################################################
877
#
878
# Ambient free modules over an integral domain.
879
#
880
###############################################################################
881
882
class FreeQuadraticModule_ambient_domain(
883
free_module.FreeModule_ambient_domain, FreeQuadraticModule_ambient):
884
"""
885
Ambient free quadratic module over an integral domain.
886
"""
887
def __init__(self, base_ring, rank, inner_product_matrix, sparse=False):
888
"""
889
EXAMPLES:
890
sage: FreeModule(PolynomialRing(GF(5),'x'), 3)
891
Ambient free module of rank 3 over the principal ideal domain
892
Univariate Polynomial Ring in x over Finite Field of size 5
893
"""
894
free_module.FreeModule_ambient.__init__(self, base_ring=base_ring, rank=rank, sparse=sparse)
895
#self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix
896
self._inner_product_matrix = inner_product_matrix
897
898
def _repr_(self):
899
"""
900
The printing representation of self.
901
902
EXAMPLES:
903
sage: R = PolynomialRing(ZZ,'x')
904
sage: M = FreeModule(R,7)
905
sage: print M
906
Ambient free module of rank 7 over the integral domain Univariate Polynomial Ring in x over Integer Ring
907
sage: print M._repr_()
908
Ambient free module of rank 7 over the integral domain Univariate Polynomial Ring in x over Integer Ring
909
910
The system representation can be overwritten, but leaves _repr_ unmodified.
911
912
sage: M.rename('M')
913
sage: print M
914
M
915
sage: print M._repr_()
916
Ambient free module of rank 7 over the integral domain Univariate Polynomial Ring in x over Integer Ring
917
918
Sparse modules print this fact.
919
920
sage: N = FreeModule(R,7,sparse=True)
921
sage: print N
922
Ambient sparse free module of rank 7 over the integral domain Univariate Polynomial Ring in x over Integer Ring
923
924
Here is a construction of a free quadratic module with generic symmetric inner product matrix.
925
926
sage: R.<a,b,c> = PolynomialRing(QQ,3)
927
sage: M = FreeModule(R, 2, inner_product_matrix=[[2*a,b],[b,2*c]])
928
sage: M
929
Ambient free quadratic module of rank 2 over the integral domain Multivariate Polynomial Ring in a, b, c over Rational Field
930
Inner product matrix:
931
[2*a b]
932
[ b 2*c]
933
sage: M.determinant()
934
-b^2 + 4*a*c
935
"""
936
if self.is_sparse():
937
return "Ambient sparse free quadratic module of rank %s over the integral domain %s\n"%(
938
self.rank(), self.base_ring() ) + \
939
"Inner product matrix:\n%s" % self.inner_product_matrix()
940
else:
941
return "Ambient free quadratic module of rank %s over the integral domain %s\n"%(
942
self.rank(), self.base_ring() ) + \
943
"Inner product matrix:\n%s" % self.inner_product_matrix()
944
945
def ambient_vector_space(self):
946
"""
947
Returns the ambient vector space, which is this free module tensored
948
with its fraction field.
949
950
EXAMPLES:
951
sage: M = ZZ^3; M.ambient_vector_space()
952
Vector space of dimension 3 over Rational Field
953
"""
954
try:
955
return self.__ambient_vector_space
956
except AttributeError:
957
self.__ambient_vector_space = FreeQuadraticModule(
958
self.base_field(), self.rank(),
959
inner_product_matrix=self.inner_product_matrix(), sparse=self.is_sparse())
960
return self.__ambient_vector_space
961
962
###############################################################################
963
#
964
# Ambient free modules over a principal ideal domain.
965
#
966
###############################################################################
967
968
class FreeQuadraticModule_ambient_pid(
969
free_module.FreeModule_ambient_pid, FreeQuadraticModule_generic_pid, FreeQuadraticModule_ambient_domain):
970
"""
971
Ambient free quadratic module over a principal ideal domain.
972
"""
973
def __init__(self, base_ring, rank, inner_product_matrix, sparse=False):
974
"""
975
Create the ambient free module of given rank over the given
976
principal ideal domain
977
978
INPUT:
979
base_ring -- a principal ideal domain
980
rank -- a non-negative integer
981
sparse -- bool (default: False)
982
inner_product_matrix -- bool (default: None)
983
984
EXAMPLES:
985
sage: ZZ^3
986
Ambient free module of rank 3 over the principal ideal domain Integer Ring
987
sage: FreeModule(ZZ,3,inner_product_matrix=Matrix([[2,-1,0],[-1,2,-1],[0,-1,2]]))
988
Ambient free quadratic module of rank 3 over the principal ideal domain Integer Ring
989
Inner product matrix:
990
[ 2 -1 0]
991
[-1 2 -1]
992
[ 0 -1 2]
993
"""
994
free_module.FreeModule_ambient_pid.__init__(self, base_ring=base_ring, rank=rank, sparse=sparse)
995
#self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix
996
self._inner_product_matrix = inner_product_matrix
997
998
def _repr_(self):
999
"""
1000
The printing representation of self.
1001
1002
EXAMPLES:
1003
sage: M = FreeModule(ZZ, 2, inner_product_matrix=[[2,-1],[-1,2]])
1004
sage: M
1005
Ambient free quadratic module of rank 2 over the principal ideal domain Integer Ring
1006
Inner product matrix:
1007
[ 2 -1]
1008
[-1 2]
1009
1010
Without a user specified inner product the class and printing is simpler.
1011
1012
sage: M = FreeModule(ZZ,7)
1013
sage: print M
1014
Ambient free module of rank 7 over the principal ideal domain Integer Ring
1015
sage: print M._repr_()
1016
Ambient free module of rank 7 over the principal ideal domain Integer Ring
1017
1018
The system representation can be overwritten, but leaves _repr_ unmodified.
1019
1020
sage: M.rename('M')
1021
sage: print M
1022
M
1023
sage: print M._repr_()
1024
Ambient free module of rank 7 over the principal ideal domain Integer Ring
1025
1026
Sparse modules print this fact.
1027
1028
sage: N = FreeModule(ZZ,7,sparse=True)
1029
sage: print N
1030
Ambient sparse free module of rank 7 over the principal ideal domain Integer Ring
1031
1032
"""
1033
if self.is_sparse():
1034
return "Ambient sparse free quadratic module of rank %s over the principal ideal domain %s\n"%(
1035
self.rank(), self.base_ring() ) + \
1036
"Inner product matrix:\n%s" % self.inner_product_matrix()
1037
else:
1038
return "Ambient free quadratic module of rank %s over the principal ideal domain %s\n"%(
1039
self.rank(), self.base_ring()) + \
1040
"Inner product matrix:\n%s" % self.inner_product_matrix()
1041
1042
###############################################################################
1043
#
1044
# Ambient free modules over a field (i.e., a vector space).
1045
#
1046
###############################################################################
1047
1048
class FreeQuadraticModule_ambient_field(
1049
free_module.FreeModule_ambient_field,
1050
FreeQuadraticModule_generic_field, FreeQuadraticModule_ambient_pid):
1051
1052
def __init__(self, base_field, dimension, inner_product_matrix, sparse=False):
1053
"""
1054
Create the ambient vector space of given dimension over the given field.
1055
1056
INPUT:
1057
base_field -- a field
1058
dimension -- a non-negative integer
1059
sparse -- bool (default: False)
1060
1061
EXAMPLES:
1062
sage: VectorSpace(QQ,3,inner_product_matrix=[[2,1,0],[1,2,0],[0,1,2]])
1063
Ambient quadratic space of dimension 3 over Rational Field
1064
Inner product matrix:
1065
[2 1 0]
1066
[1 2 0]
1067
[0 1 2]
1068
"""
1069
free_module.FreeModule_ambient_field.__init__(
1070
self, base_field=base_field, dimension=dimension, sparse=sparse)
1071
#self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix
1072
self._inner_product_matrix = inner_product_matrix
1073
1074
def _repr_(self):
1075
"""
1076
The printing representation of self.
1077
1078
EXAMPLES:
1079
sage: V = FreeModule(QQ,7)
1080
sage: print V
1081
Vector space of dimension 7 over Rational Field
1082
sage: print V._repr_()
1083
Vector space of dimension 7 over Rational Field
1084
1085
The system representation can be overwritten, but leaves _repr_ unmodified.
1086
1087
sage: V.rename('V')
1088
sage: print V
1089
V
1090
sage: print V._repr_()
1091
Vector space of dimension 7 over Rational Field
1092
1093
Sparse modules print this fact.
1094
1095
sage: U = FreeModule(QQ,7,sparse=True)
1096
sage: print U
1097
Sparse vector space of dimension 7 over Rational Field
1098
"""
1099
if self.is_sparse():
1100
return "Ambient sparse free quadratic space of dimension %s over %s\n" % ( self.rank(), self.base_ring() ) + \
1101
"Inner product matrix:\n%s" % self.inner_product_matrix()
1102
else:
1103
return "Ambient quadratic space of dimension %s over %s\n" % ( self.rank(), self.base_ring() ) + \
1104
"Inner product matrix:\n%s" % self.inner_product_matrix()
1105
1106
###############################################################################
1107
#
1108
# R-Submodule of K^n where K is the fraction field of a principal ideal domain $R$.
1109
#
1110
###############################################################################
1111
1112
class FreeQuadraticModule_submodule_with_basis_pid(
1113
free_module.FreeModule_submodule_with_basis_pid, FreeQuadraticModule_generic_pid):
1114
"""
1115
An $R$-submodule of $K^n$ with distinguished basis, where $K$ is
1116
the fraction field of a principal ideal domain $R$.
1117
"""
1118
def __init__(self, ambient, basis, inner_product_matrix,
1119
check=True, echelonize=False, echelonized_basis=None, already_echelonized=False):
1120
"""
1121
Create a free module with basis over a PID.
1122
1123
EXAMPLES:
1124
1125
sage: A = diagonal_matrix([1,2,2])
1126
sage: M = FreeQuadraticModule(ZZ,3,inner_product_matrix=A)
1127
sage: W = M.span_of_basis([[1,2,3],[4,5,6]]); W
1128
Free quadratic module of degree 3 and rank 2 over Integer Ring
1129
Basis matrix:
1130
[1 2 3]
1131
[4 5 6]
1132
Inner product matrix:
1133
[1 0 0]
1134
[0 2 0]
1135
[0 0 2]
1136
1137
sage: W = M.span_of_basis([[1,2,3/2],[4,5,6]]); W
1138
Free quadratic module of degree 3 and rank 2 over Integer Ring
1139
Basis matrix:
1140
[ 1 2 3/2]
1141
[ 4 5 6]
1142
Inner product matrix:
1143
[1 0 0]
1144
[0 2 0]
1145
[0 0 2]
1146
"""
1147
free_module.FreeModule_submodule_with_basis_pid.__init__(
1148
self, ambient=ambient, basis=basis, check=check,
1149
echelonize=echelonize, echelonized_basis=echelonized_basis, already_echelonized=already_echelonized)
1150
#self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix
1151
self._inner_product_matrix = inner_product_matrix
1152
1153
def _repr_(self):
1154
"""
1155
The printing representation of self.
1156
1157
EXAMPLES:
1158
sage: L = ZZ^8
1159
sage: E = L.submodule_with_basis([ L.gen(i) - L.gen(0) for i in range(1,8) ])
1160
sage: E # indirect doctest
1161
Free module of degree 8 and rank 7 over Integer Ring
1162
User basis matrix:
1163
[-1 1 0 0 0 0 0 0]
1164
[-1 0 1 0 0 0 0 0]
1165
[-1 0 0 1 0 0 0 0]
1166
[-1 0 0 0 1 0 0 0]
1167
[-1 0 0 0 0 1 0 0]
1168
[-1 0 0 0 0 0 1 0]
1169
[-1 0 0 0 0 0 0 1]
1170
1171
sage: M = FreeModule(ZZ,8,sparse=True)
1172
sage: N = M.submodule_with_basis([ M.gen(i) - M.gen(0) for i in range(1,8) ])
1173
sage: N # indirect doctest
1174
Sparse free module of degree 8 and rank 7 over Integer Ring
1175
User basis matrix:
1176
[-1 1 0 0 0 0 0 0]
1177
[-1 0 1 0 0 0 0 0]
1178
[-1 0 0 1 0 0 0 0]
1179
[-1 0 0 0 1 0 0 0]
1180
[-1 0 0 0 0 1 0 0]
1181
[-1 0 0 0 0 0 1 0]
1182
[-1 0 0 0 0 0 0 1]
1183
"""
1184
if self.is_sparse():
1185
s = "Sparse free quadratic module of degree %s and rank %s over %s\n"%(
1186
self.degree(), self.rank(), self.base_ring()) + \
1187
"Basis matrix:\n%s\n" % self.basis_matrix() + \
1188
"Inner product matrix:\n%s" % self.inner_product_matrix()
1189
else:
1190
s = "Free quadratic module of degree %s and rank %s over %s\n"%(
1191
self.degree(), self.rank(), self.base_ring()) + \
1192
"Basis matrix:\n%s\n" % self.basis_matrix() + \
1193
"Inner product matrix:\n%s" % self.inner_product_matrix()
1194
return s
1195
1196
def __cmp__(self, other):
1197
r"""
1198
Compare self and other.
1199
1200
Modules are ordered by their ambient spaces, then by
1201
dimension, then in order by their echelon matrices.
1202
1203
NOTE: Use the \code{is_submodule} to determine if one module
1204
is a submodule of another.
1205
1206
EXAMPLES:
1207
First we compare two equal vector spaces.
1208
sage: V = span([[1,2,3], [5,6,7], [8,9,10]], QQ)
1209
sage: W = span([[5,6,7], [8,9,10]], QQ)
1210
sage: V == W
1211
True
1212
1213
Next we compare a one dimensional space to the two dimensional space
1214
defined above.
1215
sage: M = span([[5,6,7]], QQ)
1216
sage: V == M
1217
False
1218
sage: M < V
1219
True
1220
sage: V < M
1221
False
1222
1223
We compare a $\Z$-module to the one-dimensional space above.
1224
sage: V = span([[5,6,7]], ZZ).scale(1/11); V
1225
Free module of degree 3 and rank 1 over Integer Ring
1226
Echelon basis matrix:
1227
[5/11 6/11 7/11]
1228
sage: V < M
1229
True
1230
sage: M < V
1231
False
1232
"""
1233
if self is other:
1234
return 0
1235
if not isinstance(other, free_module.FreeModule_generic):
1236
return cmp(type(self), type(other))
1237
c = cmp(self.ambient_vector_space(), other.ambient_vector_space())
1238
if c: return c
1239
c = cmp(self.dimension(), other.dimension())
1240
if c: return c
1241
# We use self.echelonized_basis_matrix() == other.echelonized_basis_matrix()
1242
# with the matrix to avoid a circular reference.
1243
return cmp(self.echelonized_basis_matrix(), other.echelonized_basis_matrix())
1244
1245
def _latex_(self):
1246
r"""
1247
Return latex representation of this free module.
1248
1249
EXAMPLES:
1250
sage: A = ZZ^3
1251
sage: M = A.span_of_basis([[1,2,3],[4,5,6]])
1252
sage: M._latex_()
1253
'\\mathrm{RowSpan}_{\\Bold{Z}}\\left(\\begin{array}{rrr}\n1 & 2 & 3 \\\\\n4 & 5 & 6\n\\end{array}\\right)'
1254
"""
1255
return "\\mathrm{RowSpan}_{%s}%s"%(latex.latex(self.base_ring()), latex.latex(self.basis_matrix()))
1256
1257
def change_ring(self, R):
1258
"""
1259
Return the free module over R obtained by coercing each
1260
element of self into a vector over the fraction field of R,
1261
then taking the resulting R-module. Raises a TypeError
1262
if coercion is not possible.
1263
1264
INPUT:
1265
R -- a principal ideal domain
1266
1267
EXAMPLES:
1268
Changing rings preserves the inner product and the user basis:
1269
1270
sage: V = QQ^3
1271
sage: W = V.subspace([[2, '1/2', 1]]); W
1272
Vector space of degree 3 and dimension 1 over Rational Field
1273
Basis matrix:
1274
[ 1 1/4 1/2]
1275
sage: W.change_ring(GF(7))
1276
Vector space of degree 3 and dimension 1 over Finite Field of size 7
1277
Basis matrix:
1278
[1 2 4]
1279
1280
sage: N = FreeModule(ZZ, 2, inner_product_matrix=[[1,-1],[2,5]])
1281
sage: N.inner_product_matrix()
1282
[ 1 -1]
1283
[ 2 5]
1284
sage: Np = N.change_ring(RDF)
1285
sage: Np.inner_product_matrix()
1286
[ 1.0 -1.0]
1287
[ 2.0 5.0]
1288
"""
1289
if self.base_ring() is R:
1290
return self
1291
K = R.fraction_field()
1292
A = self.inner_product_matrix()
1293
V = QuadraticSpace(K, self.degree(), inner_product_matrix=A)
1294
B = [ V(b) for b in self.basis() ]
1295
M = FreeQuadraticModule(R, self.degree(), inner_product_matrix=A)
1296
if self.has_user_basis():
1297
return M.span_of_basis(B)
1298
else:
1299
return M.span(B)
1300
1301
class FreeQuadraticModule_submodule_pid(
1302
free_module.FreeModule_submodule_pid, FreeQuadraticModule_submodule_with_basis_pid):
1303
"""
1304
An $R$-submodule of $K^n$ where $K$ is the fraction field of a
1305
principal ideal domain $R$.
1306
1307
EXAMPLES:
1308
sage: M = ZZ^3
1309
sage: W = M.span_of_basis([[1,2,3],[4,5,19]]); W
1310
Free module of degree 3 and rank 2 over Integer Ring
1311
User basis matrix:
1312
[ 1 2 3]
1313
[ 4 5 19]
1314
1315
We can save and load submodules and elements.
1316
sage: loads(W.dumps()) == W
1317
True
1318
sage: v = W.0 + W.1
1319
sage: loads(v.dumps()) == v
1320
True
1321
"""
1322
def __init__(self, ambient, gens, inner_product_matrix, check=True, already_echelonized=False):
1323
"""
1324
Create an embedded free module over a PID.
1325
1326
EXAMPLES:
1327
sage: V = ZZ^3
1328
sage: W = V.span([[1,2,3],[4,5,6]])
1329
sage: W
1330
Free module of degree 3 and rank 2 over Integer Ring
1331
Echelon basis matrix:
1332
[1 2 3]
1333
[0 3 6]
1334
"""
1335
free_module.FreeModule_submodule_pid.__init__(
1336
self, ambient=ambient, gens=gens, check=check, already_echelonized=already_echelonized)
1337
#self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix
1338
self._inner_product_matrix = inner_product_matrix
1339
1340
def _repr_(self):
1341
"""
1342
The printing representation of self.
1343
1344
EXAMPLES:
1345
sage: M = FreeModule(ZZ,8,inner_product_matrix=1)
1346
sage: L = M.submodule([ M.gen(i) - M.gen(0) for i in range(1,8) ])
1347
sage: print L # indirect doctest
1348
Free module of degree 8 and rank 7 over Integer Ring
1349
Echelon basis matrix:
1350
[ 1 0 0 0 0 0 0 -1]
1351
[ 0 1 0 0 0 0 0 -1]
1352
[ 0 0 1 0 0 0 0 -1]
1353
[ 0 0 0 1 0 0 0 -1]
1354
[ 0 0 0 0 1 0 0 -1]
1355
[ 0 0 0 0 0 1 0 -1]
1356
[ 0 0 0 0 0 0 1 -1]
1357
"""
1358
if self.is_sparse():
1359
s = "Sparse free module of degree %s and rank %s over %s\n"%(
1360
self.degree(), self.rank(), self.base_ring()) + \
1361
"Echelon basis matrix:\n%s"%self.basis_matrix()
1362
else:
1363
s = "Free module of degree %s and rank %s over %s\n"%(
1364
self.degree(), self.rank(), self.base_ring()) + \
1365
"Echelon basis matrix:\n%s"%self.basis_matrix()
1366
return s
1367
1368
class FreeQuadraticModule_submodule_with_basis_field(
1369
free_module.FreeModule_submodule_with_basis_field,
1370
FreeQuadraticModule_generic_field, FreeQuadraticModule_submodule_with_basis_pid):
1371
"""
1372
An embedded vector subspace with a distinguished user basis.
1373
1374
EXAMPLES:
1375
sage: M = QQ^3; W = M.submodule_with_basis([[1,2,3], [4,5,19]]); W
1376
Vector space of degree 3 and dimension 2 over Rational Field
1377
User basis matrix:
1378
[ 1 2 3]
1379
[ 4 5 19]
1380
1381
Since this is an embedded vector subspace with a distinguished user
1382
basis possibly different than the echelonized basis, the
1383
echelon_coordinates() and user coordinates() do not agree:
1384
1385
sage: V = QQ^3
1386
sage: W = V.submodule_with_basis([[1,2,3], [4,5,6]])
1387
sage: W
1388
Vector space of degree 3 and dimension 2 over Rational Field
1389
User basis matrix:
1390
[1 2 3]
1391
[4 5 6]
1392
1393
sage: v = V([1,5,9])
1394
sage: W.echelon_coordinates(v)
1395
[1, 5]
1396
sage: vector(QQ, W.echelon_coordinates(v)) * W.echelonized_basis_matrix()
1397
(1, 5, 9)
1398
1399
sage: v = V([1,5,9])
1400
sage: W.coordinates(v)
1401
[5, -1]
1402
sage: vector(QQ, W.coordinates(v)) * W.basis_matrix()
1403
(1, 5, 9)
1404
1405
We can load and save submodules:
1406
1407
sage: loads(W.dumps()) == W
1408
True
1409
1410
sage: K.<x> = FractionField(PolynomialRing(QQ,'x'))
1411
sage: M = K^3; W = M.span_of_basis([[1,1,x]])
1412
sage: loads(W.dumps()) == W
1413
True
1414
"""
1415
def __init__(self, ambient, basis, inner_product_basis,
1416
check=True, echelonize=False, echelonized_basis=None, already_echelonized=False):
1417
"""
1418
Create a vector space with given basis.
1419
1420
EXAMPLES:
1421
sage: V = QQ^3
1422
sage: W = V.span_of_basis([[1,2,3],[4,5,6]])
1423
sage: W
1424
Vector space of degree 3 and dimension 2 over Rational Field
1425
User basis matrix:
1426
[1 2 3]
1427
[4 5 6]
1428
"""
1429
free_module.FreeModule_submodule_with_basis_field.__init__(
1430
self, ambient=ambient, basis=basis, check=check,
1431
echelonize=echelonize, echelonized_basis=echelonized_basis, already_echelonized=already_echelonized)
1432
#self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix
1433
self._inner_product_matrix = inner_product_matrix
1434
1435
def _repr_(self):
1436
"""
1437
The printing representation of self.
1438
1439
EXAMPLES:
1440
sage: V = VectorSpace(QQ,5)
1441
sage: U = V.submodule([ V.gen(i) - V.gen(0) for i in range(1,5) ])
1442
sage: print U # indirect doctest
1443
Vector space of degree 5 and dimension 4 over Rational Field
1444
Basis matrix:
1445
[ 1 0 0 0 -1]
1446
[ 0 1 0 0 -1]
1447
[ 0 0 1 0 -1]
1448
[ 0 0 0 1 -1]
1449
sage: print U._repr_()
1450
Vector space of degree 5 and dimension 4 over Rational Field
1451
Basis matrix:
1452
[ 1 0 0 0 -1]
1453
[ 0 1 0 0 -1]
1454
[ 0 0 1 0 -1]
1455
[ 0 0 0 1 -1]
1456
1457
The system representation can be overwritten, but leaves _repr_ unmodified.
1458
1459
sage: U.rename('U')
1460
sage: print U
1461
U
1462
sage: print U._repr_()
1463
Vector space of degree 5 and dimension 4 over Rational Field
1464
Basis matrix:
1465
[ 1 0 0 0 -1]
1466
[ 0 1 0 0 -1]
1467
[ 0 0 1 0 -1]
1468
[ 0 0 0 1 -1]
1469
1470
Sparse vector spaces print this fact.
1471
1472
sage: V = VectorSpace(QQ,5,sparse=True)
1473
sage: U = V.submodule([ V.gen(i) - V.gen(0) for i in range(1,5) ])
1474
sage: print U # indirect doctest
1475
Sparse vector space of degree 5 and dimension 4 over Rational Field
1476
Basis matrix:
1477
[ 1 0 0 0 -1]
1478
[ 0 1 0 0 -1]
1479
[ 0 0 1 0 -1]
1480
[ 0 0 0 1 -1]
1481
"""
1482
if self.is_sparse():
1483
return "Sparse quadratic space of degree %s and dimension %s over %s\n"%(
1484
self.degree(), self.dimension(), self.base_field()) + \
1485
"Basis matrix:\n%s"%self.basis_matrix() + \
1486
"Inner product matrix:\n%s" % self.inner_product_matrix()
1487
else:
1488
return "Quadratic space of degree %s and dimension %s over %s\n"%(
1489
self.degree(), self.dimension(), self.base_field()) + \
1490
"Basis matrix:\n%s\n"%self.basis_matrix() + \
1491
"Inner product matrix:\n%s" % self.inner_product_matrix()
1492
1493
class FreeQuadraticModule_submodule_field(
1494
free_module.FreeModule_submodule_field, FreeQuadraticModule_submodule_with_basis_field):
1495
"""
1496
An embedded vector subspace with echelonized basis.
1497
1498
EXAMPLES:
1499
1500
Since this is an embedded vector subspace with echelonized basis,
1501
the echelon_coordinates() and user coordinates() agree:
1502
1503
sage: V = QQ^3
1504
sage: W = V.span([[1,2,3],[4,5,6]])
1505
sage: W
1506
Vector space of degree 3 and dimension 2 over Rational Field
1507
Basis matrix:
1508
[ 1 0 -1]
1509
[ 0 1 2]
1510
1511
sage: v = V([1,5,9])
1512
sage: W.echelon_coordinates(v)
1513
[1, 5]
1514
sage: vector(QQ, W.echelon_coordinates(v)) * W.basis_matrix()
1515
(1, 5, 9)
1516
1517
sage: v = V([1,5,9])
1518
sage: W.coordinates(v)
1519
[1, 5]
1520
sage: vector(QQ, W.coordinates(v)) * W.basis_matrix()
1521
(1, 5, 9)
1522
"""
1523
def __init__(self, ambient, gens, inner_product_matrix, check=True, already_echelonized=False):
1524
"""
1525
Create an embedded vector subspace with echelonized basis.
1526
1527
EXAMPLES:
1528
sage: V = QQ^3
1529
sage: W = V.span([[1,2,3],[4,5,6]])
1530
sage: W
1531
Vector space of degree 3 and dimension 2 over Rational Field
1532
Basis matrix:
1533
[ 1 0 -1]
1534
[ 0 1 2]
1535
"""
1536
free_module.FreeModule_submodule_field.__init__(
1537
self, ambient=ambient, gens=gens, check=check, already_echelonized=already_echelonized)
1538
#self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix
1539
self._inner_product_matrix = inner_product_matrix
1540
1541
def _repr_(self):
1542
"""
1543
The default printing representation of self.
1544
1545
EXAMPLES:
1546
sage: V = VectorSpace(QQ,5)
1547
sage: U = V.submodule([ V.gen(i) - V.gen(0) for i in range(1,5) ])
1548
sage: print U # indirect doctest
1549
Vector space of degree 5 and dimension 4 over Rational Field
1550
Basis matrix:
1551
[ 1 0 0 0 -1]
1552
[ 0 1 0 0 -1]
1553
[ 0 0 1 0 -1]
1554
[ 0 0 0 1 -1]
1555
sage: print U._repr_()
1556
Vector space of degree 5 and dimension 4 over Rational Field
1557
Basis matrix:
1558
[ 1 0 0 0 -1]
1559
[ 0 1 0 0 -1]
1560
[ 0 0 1 0 -1]
1561
[ 0 0 0 1 -1]
1562
1563
The system representation can be overwritten, but leaves _repr_ unmodified.
1564
1565
sage: U.rename('U')
1566
sage: print U
1567
U
1568
sage: print U._repr_()
1569
Vector space of degree 5 and dimension 4 over Rational Field
1570
Basis matrix:
1571
[ 1 0 0 0 -1]
1572
[ 0 1 0 0 -1]
1573
[ 0 0 1 0 -1]
1574
[ 0 0 0 1 -1]
1575
1576
Sparse vector spaces print this fact.
1577
1578
sage: V = VectorSpace(QQ,5,sparse=True)
1579
sage: U = V.submodule([ V.gen(i) - V.gen(0) for i in range(1,5) ])
1580
sage: print U # indirect doctest
1581
Sparse vector space of degree 5 and dimension 4 over Rational Field
1582
Basis matrix:
1583
[ 1 0 0 0 -1]
1584
[ 0 1 0 0 -1]
1585
[ 0 0 1 0 -1]
1586
[ 0 0 0 1 -1]
1587
"""
1588
if self.is_sparse():
1589
return "Sparse quadratic space of degree %s and dimension %s over %s\n"%(
1590
self.degree(), self.dimension(), self.base_field()) + \
1591
"Basis matrix:\n%s\n" % self.basis_matrix() + \
1592
"Inner product matrix:\n%s" % self.inner_product_matrix()
1593
else:
1594
return "Quadratic space of degree %s and dimension %s over %s\n"%(
1595
self.degree(), self.dimension(), self.base_field()) + \
1596
"Basis matrix:\n%s\n" % self.basis_matrix() + \
1597
"Inner product matrix:\n%s" % self.inner_product_matrix()
1598
1599
#class RealDoubleQuadraticSpace_class(free_module.RealDoubleVectorSpace_class, FreeQuadraticModule_ambient_field):
1600
# def __init__(self, dimension, inner_product_matrix, sparse=False):
1601
# if sparse:
1602
# raise NotImplementedError, "Sparse matrices over RDF not implemented yet"
1603
# free_module.RealDoubleVectorSpace_class.__init__(self, dimension=dimension, sparse=False)
1604
# self._inner_product_matrix = inner_product_matrix
1605
1606
#class ComplexDoubleQuadraticSpace_class(
1607
# free_module.ComplexDoubleVectorSpace_class, FreeQuadraticModule_generic): #FreeQuadraticModule_ambient_field):
1608
# def __init__(self, dimension, inner_product_matrix, sparse=False):
1609
# if sparse:
1610
# raise NotImplementedError, "Sparse matrices over CDF not implemented yet"
1611
# free_module.ComplexDoubleVectorSpace_class.__init__(self, dimension=dimension, sparse=False)
1612
# self._inner_product_matrix = inner_product_matrix
1613
1614
######################################################
1615
1616
1617