Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/quadratic_forms/quadratic_form__variable_substitutions.py
4069 views
1
"""
2
Variable Substitution, Multiplication, Division, Scaling
3
4
"""
5
#*****************************************************************************
6
# Copyright (C) 2007 William Stein and Jonathan Hanke
7
#
8
# Distributed under the terms of the GNU General Public License (GPL)
9
#
10
# This code is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
# General Public License for more details.
14
#
15
# The full text of the GPL is available at:
16
#
17
# http://www.gnu.org/licenses/
18
#*****************************************************************************
19
20
import copy
21
22
23
def swap_variables(self, r, s, in_place = False):
24
"""
25
Switch the variables `x_r` and `x_s` in the quadratic form
26
(replacing the original form if the in_place flag is True).
27
28
INPUT:
29
`r`, `s` -- integers >= 0
30
31
OUTPUT:
32
a QuadraticForm (by default, otherwise none)
33
34
EXAMPLES::
35
36
sage: Q = QuadraticForm(ZZ, 4, range(1,11))
37
sage: Q
38
Quadratic form in 4 variables over Integer Ring with coefficients:
39
[ 1 2 3 4 ]
40
[ * 5 6 7 ]
41
[ * * 8 9 ]
42
[ * * * 10 ]
43
44
45
sage: Q.swap_variables(0,2)
46
Quadratic form in 4 variables over Integer Ring with coefficients:
47
[ 8 6 3 9 ]
48
[ * 5 2 7 ]
49
[ * * 1 4 ]
50
[ * * * 10 ]
51
52
53
sage: Q.swap_variables(0,2).swap_variables(0,2)
54
Quadratic form in 4 variables over Integer Ring with coefficients:
55
[ 1 2 3 4 ]
56
[ * 5 6 7 ]
57
[ * * 8 9 ]
58
[ * * * 10 ]
59
60
"""
61
if (in_place == False):
62
Q = copy.deepcopy(self)
63
Q.__init__(self.base_ring(), self.dim(), self.coefficients())
64
Q.swap_variables(r,s,in_place=True)
65
return Q
66
67
else:
68
## Switch diagonal elements
69
tmp = self[r,r]
70
self[r,r] = self[s,s]
71
self[s,s] = tmp
72
73
## Switch off-diagonal elements
74
for i in range(self.dim()):
75
if (i != r) and (i != s):
76
tmp = self[r,i]
77
self[r,i] = self[s,i]
78
self[s,i] = tmp
79
80
81
def multiply_variable(self, c, i, in_place = False):
82
"""
83
Replace the variables `x_i` by `c*x_i` in the quadratic form
84
(replacing the original form if the in_place flag is True).
85
86
Here `c` must be an element of the base_ring defining the
87
quadratic form.
88
89
INPUT:
90
`c` -- an element of Q.base_ring()
91
92
`i` -- an integer >= 0
93
94
OUTPUT:
95
a QuadraticForm (by default, otherwise none)
96
97
EXAMPLES::
98
99
sage: Q = DiagonalQuadraticForm(ZZ, [1,9,5,7])
100
sage: Q.multiply_variable(5,0)
101
Quadratic form in 4 variables over Integer Ring with coefficients:
102
[ 25 0 0 0 ]
103
[ * 9 0 0 ]
104
[ * * 5 0 ]
105
[ * * * 7 ]
106
107
"""
108
if (in_place == False):
109
Q = copy.deepcopy(self)
110
Q.__init__(self.base_ring(), self.dim(), self.coefficients())
111
Q.multiply_variable(c,i,in_place=True)
112
return Q
113
114
else:
115
## Stretch the diagonal element
116
tmp = c * c * self[i,i]
117
self[i,i] = tmp
118
119
## Switch off-diagonal elements
120
for k in range(self.dim()):
121
if (k != i):
122
tmp = c * self[k,i]
123
self[k,i] = tmp
124
125
126
def divide_variable(self, c, i, in_place = False):
127
"""
128
Replace the variables `x_i` by `(x_i)/c` in the quadratic form
129
(replacing the original form if the in_place flag is True).
130
131
Here `c` must be an element of the base_ring defining the
132
quadratic form, and the division must be defined in the base
133
ring.
134
135
INPUT:
136
`c` -- an element of Q.base_ring()
137
138
`i` -- an integer >= 0
139
140
OUTPUT:
141
a QuadraticForm (by default, otherwise none)
142
143
EXAMPLES::
144
145
sage: Q = DiagonalQuadraticForm(ZZ, [1,9,5,7])
146
sage: Q.divide_variable(3,1)
147
Quadratic form in 4 variables over Integer Ring with coefficients:
148
[ 1 0 0 0 ]
149
[ * 1 0 0 ]
150
[ * * 5 0 ]
151
[ * * * 7 ]
152
153
"""
154
if (in_place == False):
155
Q = copy.deepcopy(self)
156
Q.__init__(self.base_ring(), self.dim(), self.coefficients())
157
Q.divide_variable(c,i,in_place=True)
158
return Q
159
160
else:
161
## Stretch the diagonal element
162
tmp = self[i,i] / (c*c)
163
self[i,i] = tmp
164
165
## Switch off-diagonal elements
166
for k in range(self.dim()):
167
if (k != i):
168
tmp = self[k,i] / c
169
self[k,i] = tmp
170
171
172
def scale_by_factor(self, c, change_value_ring_flag=False):
173
"""
174
Scale the values of the quadratic form by the number `c`, if
175
this is possible while still being defined over its base ring.
176
177
If the flag is set to true, then this will alter the value ring
178
to be the field of fractions of the original ring (if necessary).
179
180
INPUT:
181
`c` -- a scalar in the fraction field of the value ring of the form.
182
183
OUTPUT:
184
A quadratic form of the same dimension
185
186
EXAMPLES::
187
188
sage: Q = DiagonalQuadraticForm(ZZ, [3,9,18,27])
189
sage: Q.scale_by_factor(3)
190
Quadratic form in 4 variables over Integer Ring with coefficients:
191
[ 9 0 0 0 ]
192
[ * 27 0 0 ]
193
[ * * 54 0 ]
194
[ * * * 81 ]
195
196
sage: Q.scale_by_factor(1/3)
197
Quadratic form in 4 variables over Integer Ring with coefficients:
198
[ 1 0 0 0 ]
199
[ * 3 0 0 ]
200
[ * * 6 0 ]
201
[ * * * 9 ]
202
203
"""
204
## Try to scale the coefficients while staying in the ring of values.
205
new_coeff_list = [x*c for x in self.coefficients()]
206
207
## Check if we can preserve the value ring and return result. -- USE THE BASE_RING FOR NOW...
208
R = self.base_ring()
209
try:
210
list2 = [R(x) for x in new_coeff_list]
211
# This is a hack: we would like to use QuadraticForm here, but
212
# it doesn't work by scoping reasons.
213
Q = self.__class__(R, self.dim(), list2)
214
return Q
215
except:
216
if (change_value_ring_flag == False):
217
raise TypeError, "Oops! We could not rescale the lattice in this way and preserve its defining ring."
218
else:
219
raise UntestedCode, "This code is not tested by current doctests!"
220
F = R.fraction_field()
221
list2 = [F(x) for x in new_coeff_list]
222
Q = copy.deepcopy(self)
223
Q.__init__(self.dim(), F, list2, R) ## DEFINE THIS! IT WANTS TO SET THE EQUIVALENCE RING TO R, BUT WITH COEFFS IN F.
224
#Q.set_equivalence_ring(R)
225
return Q
226
227
228
def extract_variables(self, var_indices):
229
"""
230
Extract the variables (in order) whose indices are listed in
231
var_indices, to give a new quadratic form.
232
233
INPUT:
234
var_indices -- a list of integers >= 0
235
236
OUTPUT:
237
a QuadraticForm
238
239
EXAMPLES::
240
241
sage: Q = QuadraticForm(ZZ, 4, range(10)); Q
242
Quadratic form in 4 variables over Integer Ring with coefficients:
243
[ 0 1 2 3 ]
244
[ * 4 5 6 ]
245
[ * * 7 8 ]
246
[ * * * 9 ]
247
sage: Q.extract_variables([1,3])
248
Quadratic form in 2 variables over Integer Ring with coefficients:
249
[ 4 6 ]
250
[ * 9 ]
251
252
"""
253
m = len(var_indices)
254
Q = copy.deepcopy(self)
255
Q.__init__(self.base_ring(), m)
256
for i in range(m):
257
for j in range(i, m):
258
Q[i,j] = self[ var_indices[i], var_indices[j] ]
259
260
return Q
261
262
263
264
def elementary_substitution(self, c, i, j, in_place = False): ## CHECK THIS!!!
265
"""
266
Perform the substitution `x_i --> x_i + c*x_j` (replacing the
267
original form if the in_place flag is True).
268
269
INPUT:
270
`c` -- an element of Q.base_ring()
271
272
`i`, `j` -- integers >= 0
273
274
OUTPUT:
275
a QuadraticForm (by default, otherwise none)
276
277
EXAMPLES::
278
279
sage: Q = QuadraticForm(ZZ, 4, range(1,11))
280
sage: Q
281
Quadratic form in 4 variables over Integer Ring with coefficients:
282
[ 1 2 3 4 ]
283
[ * 5 6 7 ]
284
[ * * 8 9 ]
285
[ * * * 10 ]
286
287
sage: Q.elementary_substitution(c=1, i=0, j=3)
288
Quadratic form in 4 variables over Integer Ring with coefficients:
289
[ 1 2 3 6 ]
290
[ * 5 6 9 ]
291
[ * * 8 12 ]
292
[ * * * 15 ]
293
294
::
295
296
sage: R = QuadraticForm(ZZ, 4, range(1,11))
297
sage: R
298
Quadratic form in 4 variables over Integer Ring with coefficients:
299
[ 1 2 3 4 ]
300
[ * 5 6 7 ]
301
[ * * 8 9 ]
302
[ * * * 10 ]
303
304
::
305
306
sage: M = Matrix(ZZ, 4, 4, [1,0,0,1,0,1,0,0,0,0,1,0,0,0,0,1])
307
sage: M
308
[1 0 0 1]
309
[0 1 0 0]
310
[0 0 1 0]
311
[0 0 0 1]
312
sage: R(M)
313
Quadratic form in 4 variables over Integer Ring with coefficients:
314
[ 1 2 3 6 ]
315
[ * 5 6 9 ]
316
[ * * 8 12 ]
317
[ * * * 15 ]
318
319
"""
320
if (in_place == False):
321
Q = copy.deepcopy(self)
322
Q.__init__(self.base_ring(), self.dim(), self.coefficients())
323
Q.elementary_substitution(c, i, j, True)
324
return Q
325
326
else:
327
## Adjust the a_{k,j} coefficients
328
ij_old = self[i,j] ## Store this since it's overwritten, but used in the a_{j,j} computation!
329
for k in range(self.dim()):
330
if (k != i) and (k != j):
331
ans = self[j,k] + c*self[i,k]
332
self.__setitem__((j,k), ans)
333
elif (k == j):
334
ans = self[j,k] + c*ij_old + c*c*self[i,i]
335
self[j,k] = ans
336
else:
337
ans = self[j,k] + 2*c*self[i,k]
338
self[j,k] = ans
339
340
341
342
def add_symmetric(self, c, i, j, in_place = False):
343
"""
344
Performs the substitution `x_j --> x_j + c*x_i`, which has the
345
effect (on associated matrices) of symmetrically adding
346
`c * j`-th row/column to the `i`-th row/column.
347
348
NOTE: This is meant for compatibility with previous code,
349
which implemented a matrix model for this class. It is used
350
in the local_normal_form() method.
351
352
353
INPUT:
354
`c` -- an element of Q.base_ring()
355
356
`i`, `j` -- integers >= 0
357
358
OUTPUT:
359
a QuadraticForm (by default, otherwise none)
360
361
EXAMPLES::
362
363
sage: Q = QuadraticForm(ZZ, 3, range(1,7)); Q
364
Quadratic form in 3 variables over Integer Ring with coefficients:
365
[ 1 2 3 ]
366
[ * 4 5 ]
367
[ * * 6 ]
368
sage: Q.add_symmetric(-1, 1, 0)
369
Quadratic form in 3 variables over Integer Ring with coefficients:
370
[ 1 0 3 ]
371
[ * 3 2 ]
372
[ * * 6 ]
373
sage: Q.add_symmetric(-3/2, 2, 0) ## ERROR: -3/2 isn't in the base ring ZZ
374
Traceback (most recent call last):
375
...
376
RuntimeError: Oops! This coefficient can't be coerced to an element of the base ring for the quadratic form.
377
378
::
379
380
sage: Q = QuadraticForm(QQ, 3, range(1,7)); Q
381
Quadratic form in 3 variables over Rational Field with coefficients:
382
[ 1 2 3 ]
383
[ * 4 5 ]
384
[ * * 6 ]
385
sage: Q.add_symmetric(-3/2, 2, 0)
386
Quadratic form in 3 variables over Rational Field with coefficients:
387
[ 1 2 0 ]
388
[ * 4 2 ]
389
[ * * 15/4 ]
390
391
"""
392
return self.elementary_substitution(c, j, i, in_place)
393
394
395
396
397
398