cvp / src / functions_for_cvp.sage @ c7bf1784
Historique | Voir | Annoter | Télécharger (43,32 ko)
1 |
""" |
---|---|
2 |
@file functions_for_cvp.sage |
3 |
@package functions_for_cvp |
4 |
Auxiliary functions used for CVP. |
5 |
|
6 |
@author S.T. |
7 |
""" |
8 |
sys.stderr.write("Functions for CVP loading...\n") |
9 |
# |
10 |
def cvp_affine_from_chebyshev(lowerBound, upperBound): |
11 |
""" |
12 |
Compute the affine parameters to map [-1, 1] to the interval given |
13 |
as argument. |
14 |
@param: lowerBound (of the target interval) |
15 |
@param: upperBound (of the target interval) |
16 |
@return the (scalingCoefficient, offset) tuple. |
17 |
""" |
18 |
## Check bounds consistency. Bounds must differ. |
19 |
if lowerBound >= upperBound: |
20 |
return None |
21 |
scalingCoefficient = (upperBound - lowerBound) / 2 |
22 |
offset = (lowerBound + upperBound) / 2 |
23 |
return (scalingCoefficient, offset) |
24 |
# End cvp_affine_from_chebyshev |
25 |
# |
26 |
def cvp_affine_to_chebyshev(lowerBound, upperBound): |
27 |
""" |
28 |
Compute the affine parameters to map the interval given |
29 |
as argument to [-1, 1]. |
30 |
@param lowerBound (of the target interval) |
31 |
@param upperBound (of the target interval) |
32 |
@return the (scalingCoefficient, offset) tuple. |
33 |
""" |
34 |
## Check bounds consistency. Bounds must differ. |
35 |
if lowerBound >= upperBound: |
36 |
return None |
37 |
scalingCoefficient = 2 / (upperBound - lowerBound) |
38 |
## If bounds are symmetrical with relation to 0, return 0 straight before |
39 |
# attempting a division by 0. |
40 |
if lowerBound == -upperBound: |
41 |
offset = 0 |
42 |
else: |
43 |
offset = (lowerBound + upperBound) / (lowerBound - upperBound) |
44 |
return (scalingCoefficient, offset) |
45 |
# End cvp_affine_to_chebyshev |
46 |
# |
47 |
def cvp_babai(redBasis, redBasisGso, vect): |
48 |
""" |
49 |
Closest plane vector implementation as per Babaï. |
50 |
@param redBasis : a lattice basis, preferably a reduced one; |
51 |
@param redBasisGSO: the GSO of the previous basis; |
52 |
@param vector : a vector, in coordinated in the ambient |
53 |
space of the lattice |
54 |
@return the closest vector to the input, in coordinates in the |
55 |
ambient space of the lattice. |
56 |
""" |
57 |
## A deep copy is not necessary here. |
58 |
curVect = copy(vect) |
59 |
#print "cvp_babai - Vector:", vect |
60 |
## From index of last row down to 0. |
61 |
for vIndex in xrange(len(redBasis.rows())-1, -1, -1): |
62 |
curRBGSO = redBasisGso.row(vIndex) |
63 |
curVect = curVect - \ |
64 |
(round((curVect * curRBGSO) / (curRBGSO * curRBGSO)) * \ |
65 |
redBasis.row(vIndex)) |
66 |
return vect - curVect |
67 |
# End cvp_babai |
68 |
# |
69 |
def cvp_bkz_reduce(intBasis, blockSize): |
70 |
""" |
71 |
Thin and simplistic wrapper the HKZ function of the FP_LLL module. |
72 |
""" |
73 |
fplllIntBasis = FP_LLL(intBasis) |
74 |
fplllIntBasis.BKZ(blockSize) |
75 |
return fplllIntBasis._sage_() |
76 |
# End cvp_hkz_reduce. |
77 |
# |
78 |
def cvp_candidate_vectors(intVect, diffsList): |
79 |
""" |
80 |
Computes a list of best approximation vectors based on the CVP |
81 |
computed vector using the differences between this vector and the |
82 |
target function vector. |
83 |
@param intVect the vector from which candidates are built |
84 |
@param diffsList the list of the values that will be appended to the |
85 |
initial vector to form the candidates |
86 |
@return A matrix made of candidates rows or None if there is some invalid |
87 |
argument. |
88 |
@par How it works |
89 |
The idea is to create all the possible vectors based on the computed CVP |
90 |
vector and its differences to the target. Those are collected in |
91 |
diffsList.@n |
92 |
From the vector we create all the possible combinations between the original |
93 |
value and the differences in diffsList. Some of those can be equal to 0. |
94 |
They are not taken into account. If nonZeroDiffsCount is the number of |
95 |
diffsList element different from 0, there are 2^nonZeroDiffsCount |
96 |
possible variants.@n |
97 |
To compute those, we build a 2^nonZeroDiffsCount rows matrix. For the |
98 |
first element in the vector corresponding to a non-zero in diffsList, we |
99 |
switch values in the matrix at every row.@n |
100 |
For the second such element (non-zero corresponding diffsList element), we |
101 |
switch values in the matrix at every second row for a string of two similar |
102 |
values.@n |
103 |
For the third such element, change happens at every fourth row, for a |
104 |
string of four similar values. And so on... |
105 |
@par Example |
106 |
@verbatim |
107 |
vect = [10, 20, 30, 40, 50] |
108 |
diffsList = [ 1, 0, -1, 0, 1] |
109 |
vectCandMat = [[10, 20, 30, 40, 50], |
110 |
[11, 20, 30, 40, 50], |
111 |
[10, 20, 29, 40, 50], |
112 |
[11, 20, 29, 40, 50], |
113 |
[10, 20, 30, 40, 51], |
114 |
[11, 20, 30, 40, 51], |
115 |
[10, 20, 29, 40, 51], |
116 |
[11, 20, 29, 40, 51]] |
117 |
@endverbatim |
118 |
""" |
119 |
## Arguments check. |
120 |
vectLen = len(intVect) |
121 |
if vectLen != len(diffsList): |
122 |
return None |
123 |
# |
124 |
## Compute the number of diffsList elements different from 0. |
125 |
nonZeroDiffsCount = 0 |
126 |
for elem in diffsList: |
127 |
if elem != 0: |
128 |
nonZeroDiffsCount += 1 |
129 |
if nonZeroDiffsCount == 0: |
130 |
return matrix(ZZ, 0, vectLen) |
131 |
numRows = 2^nonZeroDiffsCount |
132 |
vectMat = matrix(ZZ, numRows, vectLen) |
133 |
for rowIndex in xrange(0,numRows): |
134 |
effColIndex = 0 |
135 |
for colIndex in xrange(0,vectLen): |
136 |
vectMat[rowIndex, colIndex] = intVect[colIndex] |
137 |
if diffsList[colIndex] != 0: |
138 |
if (rowIndex % 2^(effColIndex + 1)) >= 2^effColIndex: |
139 |
vectMat[rowIndex, colIndex] += diffsList[colIndex] |
140 |
effColIndex += 1 |
141 |
return vectMat |
142 |
# End cvp_candidate_vectors |
143 |
# |
144 |
def cvp_coefficients_bounds_projection(executablePath, arguments): |
145 |
""" |
146 |
Compute the min and max of the coefficients with linear |
147 |
programming projection. |
148 |
@param executablePath: the path to the binary program; |
149 |
@param arguments: a list of arguments to be givent to the binary |
150 |
@return: the min and max coefficients value arrays (in this order). |
151 |
""" |
152 |
from subprocess import check_output |
153 |
commandLine = [executablePath] + arguments |
154 |
## Get rid of output on stderr. |
155 |
devNull = open("/dev/null", "rw") |
156 |
## Run ther program. |
157 |
otp = check_output(commandLine, stderr=devNull) |
158 |
devNull.close() |
159 |
## Recover the results |
160 |
bounds = sage_eval(otp) |
161 |
minCoeffsExpList = [] |
162 |
maxCoeffsExpList = [] |
163 |
#print "bounds:", bounds |
164 |
for boundsPair in bounds: |
165 |
minCoeffsExpList.append(boundsPair[0]) |
166 |
maxCoeffsExpList.append(boundsPair[1]) |
167 |
print "minCoeffsExpList:", minCoeffsExpList |
168 |
print "maxCoeffsExpList:", maxCoeffsExpList |
169 |
return (minCoeffsExpList, maxCoeffsExpList) |
170 |
# End cvp_coefficients_bounds_projection |
171 |
|
172 |
def cvp_coefficients_bounds_projection_exps(executablePath, |
173 |
arguments, |
174 |
realField = None): |
175 |
""" |
176 |
Compute the min and max exponents of the coefficients with linear |
177 |
programming projection. |
178 |
@param executablePath: the path to the binary program; |
179 |
@param arguments: a list of arguments to be givent to the binary |
180 |
@param realField: the realField to use for floating-point conversion. |
181 |
@return: the min and max exponents arrays (in this order). |
182 |
""" |
183 |
## If no realField is givne, fall back on RR. |
184 |
if realField is None: |
185 |
realField = RR |
186 |
(minCoeffsExpList, maxCoeffsExpList) = \ |
187 |
cvp_coefficients_bounds_projection(executablePath,arguments) |
188 |
for index in xrange(0, len(minCoeffsExpList)): |
189 |
minCoeffsExpList[index] = \ |
190 |
realField(minCoeffsExpList[index]).abs().log2().floor() |
191 |
maxCoeffsExpList[index] = \ |
192 |
realField(maxCoeffsExpList[index]).abs().log2().floor() |
193 |
return (minCoeffsExpList, maxCoeffsExpList) |
194 |
# End cvp_coefficients_bounds_projection_exps |
195 |
|
196 |
def cvp_chebyshev_maxis_1k(numPoints, realField, contFracMaxErr = None): |
197 |
""" |
198 |
Compute the Chebyshev maxis for some polynomial degree (numPoints, for the |
199 |
zeros) scaled to the [lowerBound, upperBound] interval. |
200 |
The list is returned as row floating-point numbers is contFracMaxErr is None. |
201 |
Otherwise elements are transformed into rational numbers. |
202 |
""" |
203 |
if numPoints < 1: |
204 |
return None |
205 |
if numPoints == 0: |
206 |
return [0] |
207 |
## Check that realField has a "prec()" member. |
208 |
try: |
209 |
realField.prec() |
210 |
except: |
211 |
return None |
212 |
# |
213 |
maxisList = [] |
214 |
## n extrema are given by a degree (n-1) Chebyshev polynomial. |
215 |
# formulas: cos ((i * pi) / (numPoints - 1)) for i = 0,...,numPoints-1. |
216 |
# Source: https://en.wikipedia.org/wiki/Chebyshev_polynomials |
217 |
for index in xrange(0, numPoints): |
218 |
## When number of points is odd (then, the Chebyshev degree is odd two), |
219 |
# the central point is 0. */ |
220 |
if (numPoints % 2 == 1) and ((2 * index + 1) == numPoints): |
221 |
if contFracMaxErr is None: |
222 |
maxisList.append(realField(0)) |
223 |
else: |
224 |
maxisList.append(0) |
225 |
else: |
226 |
currentCheby = \ |
227 |
((realField(index) * realField(pi)) / |
228 |
realField(numPoints-1)).cos() |
229 |
#print "Current Cheby:", currentCheby |
230 |
## Result is negated to have an increasing order list. |
231 |
if contFracMaxErr is None: |
232 |
maxisList.append(-currentCheby) |
233 |
else: |
234 |
maxisList.append(-currentCheby.nearby_rational(contFracMaxErr)) |
235 |
#print "Relative error:", (currentCheby/maxisList[index]) |
236 |
return maxisList |
237 |
# End cvp_chebyshev_maxis_1k. |
238 |
# |
239 |
def cvp_chebyshev_maxis_for_interval(lowerBound, |
240 |
upperBound, |
241 |
numPoints, |
242 |
realField = None, |
243 |
contFracMaxErr = None): |
244 |
""" |
245 |
Compute the Chebyshev maxis for some polynomial degree (numPoints, for the |
246 |
maxis) scaled to the [lowerBound, upperBound] interval. |
247 |
If no contFracMaxErr argument is given, we return the list as "raw" |
248 |
floating-points. Otherwise, rational numbers are returned. |
249 |
""" |
250 |
## Arguments check. |
251 |
if lowerBound >= upperBound: |
252 |
return None |
253 |
if numPoints < 1: |
254 |
return None |
255 |
## If no realField argument is given try to retrieve it from the |
256 |
# bounds. If impossible (e.g. rational bound), fall back on RR. |
257 |
if realField is None: |
258 |
try: |
259 |
### Force failure if parent does not have prec() member. |
260 |
lowerBound.parent().prec() |
261 |
### If no exception is thrown, set realField. |
262 |
realField = lowerBound.parent() |
263 |
except: |
264 |
realField = RR |
265 |
#print "Real field:", realField |
266 |
## We want "raw"floating-point nodes to only have one final rounding. |
267 |
chebyshevMaxisList = \ |
268 |
cvp_chebyshev_maxis_1k(numPoints, realField) |
269 |
scalingFactor, offset = cvp_affine_from_chebyshev(lowerBound, upperBound) |
270 |
for index in xrange(0, len(chebyshevMaxisList)): |
271 |
chebyshevMaxisList[index] = \ |
272 |
chebyshevMaxisList[index] * scalingFactor + offset |
273 |
if not contFracMaxErr is None: |
274 |
chebyshevMaxisList[index] = \ |
275 |
chebyshevMaxisList[index].nearby_rational(contFracMaxErr) |
276 |
return chebyshevMaxisList |
277 |
# End cvp_chebyshev_maxis_for_interval. |
278 |
# |
279 |
def cvp_chebyshev_zeros_1k(numPoints, realField, contFracMaxErr = None): |
280 |
""" |
281 |
Compute the Chebyshev zeros for some polynomial degree (numPoints, for the |
282 |
zeros) scaled to the [lowerBound, upperBound] interval. |
283 |
The list is returned as row floating-point numbers is contFracMaxErr is None. |
284 |
Otherwise elements are transformed into rational numbers. |
285 |
""" |
286 |
if numPoints < 1: |
287 |
return None |
288 |
if numPoints == 0: |
289 |
return [0] |
290 |
## Check that realField has a "prec()" member. |
291 |
try: |
292 |
realField.prec() |
293 |
except: |
294 |
return None |
295 |
# |
296 |
zerosList = [] |
297 |
## formulas: cos (((2*i - 1) * pi) / (2*numPoints)) for i = 1,...,numPoints. |
298 |
# If i is -1-shifted, as in the following loop, formula is |
299 |
# cos (((2*i + 1) * pi) / (2*numPoints)) for i = 0,...,numPoints-1. |
300 |
for index in xrange(0, numPoints): |
301 |
## When number of points is odd (then, the Chebyshev degree is odd two), |
302 |
# the central point is 0. */ |
303 |
if (numPoints % 2 == 1) and ((2 * index + 1) == numPoints): |
304 |
if contFracMaxErr is None: |
305 |
zerosList.append(realField(0)) |
306 |
else: |
307 |
zerosList.append(0) |
308 |
else: |
309 |
currentCheby = \ |
310 |
((realField(2*index+1) * realField(pi)) / |
311 |
realField(2*numPoints)).cos() |
312 |
#print "Current Cheby:", currentCheby |
313 |
## Result is negated to have an increasing order list. |
314 |
if contFracMaxErr is None: |
315 |
zerosList.append(-currentCheby) |
316 |
else: |
317 |
zerosList.append(-currentCheby.nearby_rational(contFracMaxErr)) |
318 |
#print "Relative error:", (currentCheby/zerosList[index]) |
319 |
return zerosList |
320 |
# End cvp_chebyshev_zeros_1k. |
321 |
# |
322 |
def cvp_chebyshev_zeros_for_interval(lowerBound, |
323 |
upperBound, |
324 |
numPoints, |
325 |
realField = None, |
326 |
contFracMaxErr = None): |
327 |
""" |
328 |
Compute the Chebyshev zeros for some polynomial degree (numPoints, for the |
329 |
zeros) scaled to the [lowerBound, upperBound] interval. |
330 |
If no contFracMaxErr argument is given, we return the list as "raw" |
331 |
floating-points. Otherwise, rational numbers are returned. |
332 |
""" |
333 |
## Arguments check. |
334 |
if lowerBound >= upperBound: |
335 |
return None |
336 |
if numPoints < 1: |
337 |
return None |
338 |
## If no realField argument is given try to retrieve it from the |
339 |
# bounds. If impossible (e.g. rational bound), fall back on RR. |
340 |
if realField is None: |
341 |
try: |
342 |
### Force failure if parent does not have prec() member. |
343 |
lowerBound.parent().prec() |
344 |
### If no exception is thrown, set realField. |
345 |
realField = lowerBound.parent() |
346 |
except: |
347 |
realField = RR |
348 |
#print "Real field:", realField |
349 |
## We want "raw"floating-point nodes to only have one final rounding. |
350 |
chebyshevZerosList = \ |
351 |
cvp_chebyshev_zeros_1k(numPoints, realField) |
352 |
scalingFactor, offset = cvp_affine_from_chebyshev(lowerBound, upperBound) |
353 |
for index in xrange(0, len(chebyshevZerosList)): |
354 |
chebyshevZerosList[index] = \ |
355 |
chebyshevZerosList[index] * scalingFactor + offset |
356 |
if not contFracMaxErr is None: |
357 |
chebyshevZerosList[index] = \ |
358 |
chebyshevZerosList[index].nearby_rational(contFracMaxErr) |
359 |
return chebyshevZerosList |
360 |
# End cvp_chebyshev_zeros_for_interval. |
361 |
# |
362 |
def cvp_common_scaling_exp(precision, |
363 |
precisionFraction = None): |
364 |
""" |
365 |
Compute the common scaling factor (a power of 2). |
366 |
The exponent is a fraction of the precision; |
367 |
A extra factor is computed for the vector, |
368 |
exra factors are computed for the basis vectors, all in the corresponding |
369 |
functions. |
370 |
""" |
371 |
## Set a default value for the precisionFraction to 1/2. |
372 |
if precisionFraction is None: |
373 |
precisionFraction = 3/4 |
374 |
""" |
375 |
minBasisVectsNorm = oo |
376 |
currentNorm = 0 |
377 |
for vect in floatBasis.rows(): |
378 |
currentNorm = vect.norm() |
379 |
print "Current norm:", currentNorm |
380 |
if currentNorm < minBasisVectsNorm: |
381 |
minBasisVectsNorm = currentNorm |
382 |
currentNorm = funcVect.norm() |
383 |
print "Current norm:", currentNorm |
384 |
if currentNorm < minBasisVectsNorm: |
385 |
minBasisVectsNorm = currentNorm |
386 |
## Check if a push is need because the smallest norm is below 0. |
387 |
powerForMinNorm = floor(log(minBasisVectsNorm)/log2) |
388 |
print "Power for min norm :", powerForMinNorm |
389 |
print "Power for precision:", ceil(precision*precisionFraction) |
390 |
if powerForMinNorm < 0: |
391 |
return 2^(ceil(precision*precisionFraction) - powerFromMinNorm) |
392 |
else: |
393 |
""" |
394 |
return ceil(precision * precisionFraction) |
395 |
# End cvp_common_scaling_factor. |
396 |
# |
397 |
def cvp_cvp_polynomial(func, |
398 |
lowerBound, |
399 |
upperBound, |
400 |
coeffsExpList, |
401 |
coeffsPrecList, |
402 |
minCoeffsBoundExpList, |
403 |
maxCoeffsBoundExpList, |
404 |
pointsList, |
405 |
realField): |
406 |
""" |
407 |
Compute a polynomial based on a CVP vector for a function approximation. |
408 |
""" |
409 |
## Build the basis for CVP. |
410 |
### Common scaling exponent. |
411 |
commonScalingExp = cvp_common_scaling_exp(realField.prec()) |
412 |
### Monomials list derived from exponenets list. |
413 |
monomialsList = cvp_monomials_list(coeffsExpList) |
414 |
### Float basis first |
415 |
floatBasis = cvp_float_basis(monomialsList, pointsList, realField) |
416 |
### Integral basis. |
417 |
extraScalingExpsList = \ |
418 |
cvp_extra_basis_scaling_exps(coeffsPrecList, minCoeffsBoundExpList) |
419 |
intBasis = \ |
420 |
cvp_int_basis(floatBasis, commonScalingExp, extraScalingExpsList) |
421 |
### The reduced basis. |
422 |
redIntBasis = cvp_lll_reduce(intBasis) |
423 |
### The reduced basis GSO. |
424 |
(redIntBasisGso, mu) = redIntBasis.gram_schmidt() |
425 |
## Function vector. |
426 |
#### Floating-point vector. |
427 |
floatFuncVect = \ |
428 |
cvp_float_vector_for_approx(func, pointsList, realField) |
429 |
extraFuncScalingExp = \ |
430 |
cvp_extra_function_scaling_exp(floatBasis, |
431 |
floatFuncVect, |
432 |
maxCoeffsBoundExpList) |
433 |
#### Integral vector. |
434 |
intFuncVect = \ |
435 |
cvp_int_vector_for_approx(floatFuncVect, |
436 |
commonScalingExp, |
437 |
extraFuncScalingExp) |
438 |
## CPV vector |
439 |
### In ambient basis. |
440 |
cvpVectInAmbient = cvp_babai(redIntBasis, redIntBasisGso, intFuncVect) |
441 |
### In intBasis. |
442 |
cvpVectInIntBasis = cvp_vector_in_basis(cvpVectInAmbient, intBasis) |
443 |
## Polynomial coefficients |
444 |
cvpPolynomialCoeffs = \ |
445 |
cvp_polynomial_coeffs_from_vect(cvpVectInIntBasis, |
446 |
coeffsPrecList, |
447 |
minCoeffsBoundExpList, |
448 |
extraFuncScalingExp) |
449 |
#print "CVP polynomial coefficients:" |
450 |
#print cvpPolynomialCoeffs |
451 |
## Polynomial in Sage. |
452 |
cvpPolySa = \ |
453 |
cvp_polynomial_from_coeffs_and_exps(cvpPolynomialCoeffs, |
454 |
coeffsExpList, |
455 |
realField[x]) |
456 |
#print cvpPolySa |
457 |
return cvpPolySa |
458 |
# End cvp_cvp_polynomial. |
459 |
# |
460 |
def cvp_evaluation_points_list(funct, |
461 |
maxDegree, |
462 |
lowerBound, |
463 |
upperBound, |
464 |
realField = None): |
465 |
""" |
466 |
Compute a list of points for the vector creation. |
467 |
Strategy: |
468 |
- compute the zeros of the function-remez; |
469 |
- compute the zeros of the function-rounded_remez; |
470 |
- compute the Chebyshev points. |
471 |
Merge the whole thing. |
472 |
""" |
473 |
|
474 |
# End cvp_evaluation_points_list. |
475 |
# |
476 |
def cvp_extra_basis_scaling_exps(precsList, minExponentsList): |
477 |
""" |
478 |
Computes the exponents for the extra scaling down of the elements of the |
479 |
basis. |
480 |
This extra scaling down is necessary when there are elements of the |
481 |
basis that have negative exponents. |
482 |
""" |
483 |
extraScalingExpsList = [] |
484 |
for minExp, prec in zip(minExponentsList, precsList): |
485 |
if minExp - prec < 0: |
486 |
extraScalingExpsList.append(minExp - prec) |
487 |
else: |
488 |
extraScalingExpsList.append(0) |
489 |
return extraScalingExpsList |
490 |
# End cvp_extra_basis_scaling_exps. |
491 |
# |
492 |
def cvp_extra_function_scaling_exp(floatBasis, |
493 |
floatFuncVect, |
494 |
maxExponentsList): |
495 |
""" |
496 |
Compute the extra scaling exponent for the function vector in ordre to |
497 |
guarantee that the maximum exponent can be reached for each element of the |
498 |
basis. |
499 |
""" |
500 |
## Check arguments |
501 |
if floatBasis.nrows() == 0 or \ |
502 |
floatBasis.ncols() == 0 or \ |
503 |
len(floatFuncVect) == 0: |
504 |
return 1 |
505 |
if len(maxExponentsList) != floatBasis.nrows(): |
506 |
return None |
507 |
## Compute the log of the norm of the function vector. |
508 |
funcVectNormLog = log(floatFuncVect.norm()) |
509 |
## Compute the extra scaling factor for each vector of the basis. |
510 |
# for norms ratios an maxExponentsList. |
511 |
extraScalingExp = 0 |
512 |
for (row, maxExp) in zip(floatBasis.rows(),maxExponentsList): |
513 |
rowNormLog = log(row.norm()) |
514 |
normsRatioLog2 = floor((funcVectNormLog - rowNormLog) / log2) |
515 |
#print "Current norms ratio log2:", normsRatioLog2 |
516 |
scalingExpCandidate = normsRatioLog2 - maxExp |
517 |
#print "Current scaling exponent candidate:", scalingExpCandidate |
518 |
if scalingExpCandidate < 0: |
519 |
if -scalingExpCandidate > extraScalingExp: |
520 |
extraScalingExp = -scalingExpCandidate |
521 |
return extraScalingExp |
522 |
# End cvp_extra_function_scaling_exp. |
523 |
# |
524 |
def cvp_float_basis(monomialsList, pointsList, realField): |
525 |
""" |
526 |
For a given monomials list and points list, compute the floating-point |
527 |
basis matrix. |
528 |
""" |
529 |
numRows = len(monomialsList) |
530 |
numCols = len(pointsList) |
531 |
if numRows == 0 or numCols == 0: |
532 |
return matrix(realField, 0, 0) |
533 |
# |
534 |
floatBasis = matrix(realField, numRows, numCols) |
535 |
for rIndex in xrange(0, numRows): |
536 |
for cIndex in xrange(0, numCols): |
537 |
floatBasis[rIndex,cIndex] = \ |
538 |
monomialsList[rIndex](realField(pointsList[cIndex])) |
539 |
return floatBasis |
540 |
# End cvp_float_basis |
541 |
# |
542 |
def cvp_float_vector_for_approx(func, |
543 |
basisPointsList, |
544 |
realField): |
545 |
""" |
546 |
Compute a floating-point vector for the function and the points list. |
547 |
""" |
548 |
# |
549 |
## Some local variables. |
550 |
basisPointsNum = len(basisPointsList) |
551 |
# |
552 |
## |
553 |
vVect = vector(realField, basisPointsNum) |
554 |
for vIndex in xrange(0,basisPointsNum): |
555 |
vVect[vIndex] = \ |
556 |
func(basisPointsList[vIndex]) |
557 |
return vVect |
558 |
# End cvp_float_vector_for_approx. |
559 |
# |
560 |
def cvp_func_abs_max_for_points(func, pointsList): |
561 |
""" |
562 |
Compute the maximum absolute value of a function for a list of |
563 |
points. |
564 |
If several points yield the same value and this value is the maximum, |
565 |
an unspecified point of this set is returned. |
566 |
@return (theMaxPoint, theMaxValue) |
567 |
""" |
568 |
evalDict = dict() |
569 |
if len(pointsList) == 0: |
570 |
return None |
571 |
# |
572 |
for pt in pointsList: |
573 |
evalDict[abs(func(pt))] = pt |
574 |
maxAbs = max(evalDict.keys()) |
575 |
return (evalDict[maxAbs], maxAbs) |
576 |
# End cvp_func_abs_max_for_points |
577 |
# |
578 |
def cvp_hkz_reduce(intBasis): |
579 |
""" |
580 |
Thin and simplistic wrapper the HKZ function of the FP_LLL module. |
581 |
""" |
582 |
fplllIntBasis = FP_LLL(intBasis) |
583 |
fplllIntBasis.HKZ() |
584 |
return fplllIntBasis._sage_() |
585 |
# End cvp_hkz_reduce. |
586 |
# |
587 |
def cvp_int_basis(floatBasis, |
588 |
commonScalingExp, |
589 |
extraScalingExpsList): |
590 |
""" |
591 |
From the float basis, the common scaling factor and the extra exponents |
592 |
compute the integral basis. |
593 |
""" |
594 |
## Checking arguments. |
595 |
if floatBasis.nrows() != len(extraScalingExpsList): |
596 |
return None |
597 |
intBasis = matrix(ZZ, floatBasis.nrows(), floatBasis.ncols()) |
598 |
for rIndex in xrange(0, floatBasis.nrows()): |
599 |
for cIndex in xrange(0, floatBasis.ncols()): |
600 |
intBasis[rIndex, cIndex] = \ |
601 |
(floatBasis[rIndex, cIndex] * \ |
602 |
2^(commonScalingExp + extraScalingExpsList[rIndex])).round() |
603 |
return intBasis |
604 |
# End cvp_int_basis. |
605 |
# |
606 |
def cvp_int_vector_for_approx(floatVect, commonScalingExp, extraScalingExp): |
607 |
""" |
608 |
Compute the integral version of the function vector. |
609 |
""" |
610 |
totalScalingFactor = 2^(commonScalingExp + extraScalingExp) |
611 |
intVect = vector(ZZ, len(floatVect)) |
612 |
for index in xrange(0, len(floatVect)): |
613 |
intVect[index] = (floatVect[index] * totalScalingFactor).round() |
614 |
return intVect |
615 |
# End cvp_int_vector_for_approx. |
616 |
# |
617 |
def cvp_lll_reduce(intBasis): |
618 |
""" |
619 |
Thin and simplistic wrapper around the LLL function |
620 |
""" |
621 |
return intBasis.LLL() |
622 |
# End cvp_lll_reduce. |
623 |
# |
624 |
def cvp_monomials_list(exponentsList, varName = None): |
625 |
""" |
626 |
Create a list of monomials corresponding to the given exponentsList. |
627 |
Monomials are defined as functions. |
628 |
""" |
629 |
monomialsList = [] |
630 |
for exponent in exponentsList: |
631 |
if varName is None: |
632 |
monomialsList.append((x^exponent).function(x)) |
633 |
else: |
634 |
monomialsList.append((varName^exponent).function(varName)) |
635 |
return monomialsList |
636 |
# End cvp_monomials_list. |
637 |
# |
638 |
def cvp_polynomial_coeffs_from_vect(cvpVectInBasis, |
639 |
coeffsPrecList, |
640 |
minCoeffsExpList, |
641 |
extraFuncScalingExp): |
642 |
""" |
643 |
Computes polynomial coefficients out of the elements of the CVP vector. |
644 |
@todo |
645 |
Rewrite the code with a single exponentiation, at the very end. |
646 |
""" |
647 |
numElements = len(cvpVectInBasis) |
648 |
## Arguments check. |
649 |
if numElements != len(minCoeffsExpList) or \ |
650 |
numElements != len(coeffsPrecList): |
651 |
return None |
652 |
polynomialCoeffsList = [] |
653 |
for index in xrange(0, numElements): |
654 |
currentCoeff = cvp_round_to_bits(cvpVectInBasis[index], |
655 |
coeffsPrecList[index]) |
656 |
#print "cvp_polynomial_coeffs - current coefficient rounded:", currentCoeff |
657 |
currentCoeff *= 2^(minCoeffsExpList[index]) |
658 |
#print "cvp_polynomial_coeffs - current coefficient scaled :", currentCoeff |
659 |
currentCoeff *= 2^(-coeffsPrecList[index]) |
660 |
#print "cvp_polynomial_coeffs - current coefficient prec corrected :", currentCoeff |
661 |
currentCoeff *= 2^(-extraFuncScalingExp) |
662 |
#print "cvp_polynomial_coeffs - current coefficient extra func scaled :", currentCoeff |
663 |
polynomialCoeffsList.append(currentCoeff) |
664 |
return polynomialCoeffsList |
665 |
# En polynomial_coeffs_from_vect. |
666 |
# |
667 |
def cvp_polynomial_error_func_maxis(funcSa, |
668 |
polySa, |
669 |
lowerBoundSa, |
670 |
upperBoundSa, |
671 |
realField = None, |
672 |
contFracMaxErr = None): |
673 |
""" |
674 |
For a given function, approximation polynomial and interval (given |
675 |
as bounds) compute the maxima of the functSa - polySo on the interval. |
676 |
Also computes the infnorm of the error function. |
677 |
""" |
678 |
## Arguments check. |
679 |
# @todo. |
680 |
## If no realField argument is given try to retrieve it from the |
681 |
# bounds. If impossible (e.g. rational bound), fall back on RR. |
682 |
if realField is None: |
683 |
try: |
684 |
### Force failure if parent does not have prec() member. |
685 |
lowerBound.parent().prec() |
686 |
### If no exception is thrown, set realField. |
687 |
realField = lowerBound.parent() |
688 |
except: |
689 |
realField = RR |
690 |
#print "Real field:", realField |
691 |
## Compute the Sollya version of the function. |
692 |
funcAsStringSa = funcSa._assume_str().replace("_SAGE_VAR_","",100) |
693 |
funcSo = pobyso_parse_string(funcAsStringSa) |
694 |
if pobyso_is_error_so_sa(funcSo): |
695 |
pobyso_clear_obj(funcSo) |
696 |
return None |
697 |
## Compute the Sollya version of the polynomial. |
698 |
## The conversion is made from a floating-point coefficients polynomial. |
699 |
try: |
700 |
polySa.base_ring().prec() |
701 |
convFloatPolySa = polySa |
702 |
except: |
703 |
convFloatPolySa = realField[polySa.variables()[0]](polySa) |
704 |
polySo = pobyso_float_poly_sa_so(convFloatPolySa) |
705 |
if pobyso_is_error_so_sa(funcSo): |
706 |
pobyso_clear_obj(funcSo) |
707 |
pobyso_clear_obj(polySo) |
708 |
return None |
709 |
## Copy both funcSo and polySo as they are needed later for the infnorm.. |
710 |
errorFuncSo = sollya_lib_build_function_sub(sollya_lib_copy_obj(funcSo), |
711 |
sollya_lib_copy_obj(polySo)) |
712 |
if pobyso_is_error_so_sa(errorFuncSo): |
713 |
pobyso_clear_obj(errorFuncSo) |
714 |
return None |
715 |
## Compute the derivative. |
716 |
diffErrorFuncSo = pobyso_diff_so_so(errorFuncSo) |
717 |
pobyso_clear_obj(errorFuncSo) |
718 |
if pobyso_is_error_so_sa(diffErrorFuncSo): |
719 |
pobyso_clear_obj(diffErrorFuncSo) |
720 |
return None |
721 |
## Compute the interval. |
722 |
intervalSo = pobyso_range_from_bounds_sa_so(lowerBound, upperBound) |
723 |
if pobyso_is_error_so_sa(intervalSo): |
724 |
pobyso_clear_obj(diffErrorFuncSo) |
725 |
pobyso_clear_obj(intervalSo) |
726 |
return None |
727 |
## Compute the infnorm of the error function. |
728 |
errFuncSupNormSa = pobyso_supnorm_so_sa(polySo, |
729 |
funcSo, |
730 |
intervalSo, |
731 |
realFieldSa = realField) |
732 |
pobyso_clear_obj(polySo) |
733 |
pobyso_clear_obj(funcSo) |
734 |
## Compute the zeros of the derivative. |
735 |
errorFuncMaxisSo = pobyso_dirty_find_zeros_so_so(diffErrorFuncSo, intervalSo) |
736 |
pobyso_clear_obj(diffErrorFuncSo) |
737 |
pobyso_clear_obj(intervalSo) |
738 |
if pobyso_is_error_so_sa(errorFuncMaxisSo): |
739 |
pobyso_clear_obj(errorFuncMaxisSo) |
740 |
return None |
741 |
errorFuncMaxisSa = pobyso_float_list_so_sa(errorFuncMaxisSo) |
742 |
pobyso_clear_obj(errorFuncMaxisSo) |
743 |
## If required, convert the numbers to rational numbers. |
744 |
if not contFracMaxErr is None: |
745 |
for index in xrange(0, len(errorFuncMaxisSa)): |
746 |
errorFuncMaxisSa[index] = \ |
747 |
errorFuncMaxisSa[index].nearby_rational(contFracMaxErr) |
748 |
return (errorFuncMaxisSa, errFuncSupNormSa) |
749 |
# End cvp_polynomial_error_func_maxis |
750 |
# |
751 |
def cvp_polynomial_from_coeffs_and_exps(coeffsList, |
752 |
expsList, |
753 |
polyField = None, |
754 |
theVar = None): |
755 |
""" |
756 |
Build a polynomial in the classical monomials (possibly lacunary) basis |
757 |
from a list of coefficients and a list of exponents. The polynomial is in |
758 |
the polynomial field given as argument. |
759 |
""" |
760 |
if len(coeffsList) != len(expsList): |
761 |
return None |
762 |
## If no variable is given, "x" is used. |
763 |
## If no polyField is given, we fall back on a polynomial field on RR. |
764 |
if theVar is None: |
765 |
if polyField is None: |
766 |
theVar = x |
767 |
polyField = RR[theVar] |
768 |
else: |
769 |
theVar = var(polyField.variable_name()) |
770 |
else: ### theVar is set. |
771 |
### No polyField, fallback on RR[theVar]. |
772 |
if polyField is None: |
773 |
polyField = RR[theVar] |
774 |
else: ### Both the polyFiled and theVar are set: create a new polyField |
775 |
# with theVar. The original polyField is not affected by the |
776 |
# change. |
777 |
polyField = polyField.change_var(theVar) |
778 |
## Seed the polynomial. |
779 |
poly = polyField(0) |
780 |
## Append the terms. |
781 |
for coeff, exp in zip(coeffsList, expsList): |
782 |
poly += polyField(coeff * theVar^exp) |
783 |
return poly |
784 |
# End cvp_polynomial_from_coeffs_and_exps. |
785 |
# |
786 |
def cvp_remez_all_poly_error_func_maxis(funct, |
787 |
maxDegree, |
788 |
lowerBound, |
789 |
upperBound, |
790 |
precsList, |
791 |
realField = None, |
792 |
contFracMaxErr = None): |
793 |
""" |
794 |
For a given function f, a degree and an interval, compute the |
795 |
maxima of the (f-remez_d(f)) function and those of the (f-truncRemez_d(f)) |
796 |
function over the interval. |
797 |
""" |
798 |
## If no realField argument is given try to retrieve it from the |
799 |
# bounds. If impossible (e.g. rational bound), fall back on RR. |
800 |
if realField is None: |
801 |
try: |
802 |
### Force failure if parent does not have prec() member. |
803 |
lowerBound.parent().prec() |
804 |
### If no exception is thrown, set realField. |
805 |
realField = lowerBound.parent() |
806 |
except: |
807 |
realField = RR |
808 |
#print "Real field:", realField |
809 |
funcSa = func |
810 |
funcAsStringSa = func._assume_str().replace("_SAGE_VAR_","",100) |
811 |
print "Function as a string:", funcAsStringSa |
812 |
## Create the Sollya version of the function and compute the |
813 |
# Remez approximant |
814 |
funcSo = pobyso_parse_string(funcAsStringSa) |
815 |
pStarSo = pobyso_remez_canonical_sa_so(funcAsStringSa, |
816 |
maxDegree, |
817 |
lowerBound, |
818 |
upperBound) |
819 |
## Compute the error function and its derivative |
820 |
### First create the error function with copies since they are needed later. |
821 |
errorFuncSo = sollya_lib_build_function_sub(sollya_lib_copy_obj(pStarSo), |
822 |
sollya_lib_copy_obj(funcSo)) |
823 |
intervalSo = pobyso_range_from_bounds_sa_so(lowerBound, upperBound) |
824 |
diffErrorFuncSo = pobyso_diff_so_so(errorFuncSo) |
825 |
pobyso_clear_obj(errorFuncSo) |
826 |
## Compute the zeros of the derivative. |
827 |
errorFuncMaxisSo = pobyso_dirty_find_zeros_so_so(diffErrorFuncSo, intervalSo) |
828 |
pobyso_clear_obj(diffErrorFuncSo) |
829 |
errorFuncMaxisSa = pobyso_float_list_so_sa(errorFuncMaxisSo) |
830 |
pobyso_clear_obj(errorFuncMaxisSo) |
831 |
## Compute the truncated Remez polynomial and the error function. |
832 |
truncFormatListSo = pobyso_build_list_of_ints_sa_so(*precsList) |
833 |
pTruncSo = pobyso_round_coefficients_so_so(pStarSo, truncFormatListSo) |
834 |
pobyso_clear_obj(pStarSo) |
835 |
### Compute the error function. This time we consume both the function |
836 |
# and the polynomial. |
837 |
errorFuncSo = sollya_lib_build_function_sub(pTruncSo, funcSo) |
838 |
## Compute the derivative. |
839 |
diffErrorFuncSo = pobyso_diff_so_so(errorFuncSo) |
840 |
pobyso_clear_obj(errorFuncSo) |
841 |
## Compute the zeros of the derivative. |
842 |
errorFuncMaxisSo = pobyso_dirty_find_zeros_so_so(diffErrorFuncSo, intervalSo) |
843 |
pobyso_clear_obj(diffErrorFuncSo) |
844 |
pobyso_clear_obj(intervalSo) |
845 |
errorFuncTruncMaxisSa = pobyso_float_list_so_sa(errorFuncMaxisSo) |
846 |
pobyso_clear_obj(errorFuncMaxisSo) |
847 |
## Merge with the first list, removing duplicates if any. |
848 |
errorFuncMaxisSa.extend(elem for elem in errorFuncTruncMaxisSa \ |
849 |
if elem not in errorFuncMaxisSa) |
850 |
errorFuncMaxisSa.sort() |
851 |
## If required, convert the numbers to rational numbers. |
852 |
if not contFracMaxErr is None: |
853 |
for index in xrange(0, len(errorFuncMaxisSa)): |
854 |
errorFuncMaxisSa[index] = \ |
855 |
errorFuncMaxisSa[index].nearby_rational(contFracMaxErr) |
856 |
return errorFuncMaxisSa |
857 |
# End cvp_remez_all_poly_error_func_maxis. |
858 |
# |
859 |
def cvp_remez_all_poly_error_func_zeros(funct, |
860 |
maxDegree, |
861 |
lowerBound, |
862 |
upperBound, |
863 |
precsList, |
864 |
realField = None, |
865 |
contFracMaxErr = None): |
866 |
""" |
867 |
For a given function f, a degree and an interval, compute the |
868 |
zeros of the (f-remez_d(f)) function and those of the (f-truncRemez_d(f)) |
869 |
function over the interval. |
870 |
""" |
871 |
## If no realField argument is given try to retrieve it from the |
872 |
# bounds. If impossible (e.g. rational bound), fall back on RR. |
873 |
if realField is None: |
874 |
try: |
875 |
### Force failure if parent does not have prec() member. |
876 |
lowerBound.parent().prec() |
877 |
### If no exception is thrown, set realField. |
878 |
realField = lowerBound.parent() |
879 |
except: |
880 |
realField = RR |
881 |
#print "Real field:", realField |
882 |
funcSa = func |
883 |
funcAsStringSa = func._assume_str().replace("_SAGE_VAR_","",100) |
884 |
print "Function as a string:", funcAsStringSa |
885 |
## Create the Sollya version of the function and compute the |
886 |
# Remez approximant |
887 |
funcSo = pobyso_parse_string(funcAsStringSa) |
888 |
pStarSo = pobyso_remez_canonical_sa_so(funcAsStringSa, |
889 |
maxDegree, |
890 |
lowerBound, |
891 |
upperBound) |
892 |
## Compute the zeroes of the error function. |
893 |
### First create the error function with copies since they are needed later. |
894 |
errorFuncSo = sollya_lib_build_function_sub(sollya_lib_copy_obj(pStarSo), |
895 |
sollya_lib_copy_obj(funcSo)) |
896 |
intervalSo = pobyso_range_from_bounds_sa_so(lowerBound, upperBound) |
897 |
errorFuncZerosSo = pobyso_dirty_find_zeros_so_so(errorFuncSo, intervalSo) |
898 |
pobyso_clear_obj(errorFuncSo) # Clears funcSo and pStarSo as well. |
899 |
#print "Zeroes of the error function from Sollya:" |
900 |
#pobyso_autoprint(errorFuncZerosSo) |
901 |
errorFuncZerosSa = pobyso_float_list_so_sa(errorFuncZerosSo) |
902 |
pobyso_clear_obj(errorFuncZerosSo) |
903 |
#print "\nZeroes of the error function from Sage:" |
904 |
#print errorFuncZerosSa |
905 |
# |
906 |
## Deal with the truncated polynomial now. |
907 |
### Create the formats list. Notice the "*" before the list variable name. |
908 |
truncFormatListSo = pobyso_build_list_of_ints_sa_so(*precsList) |
909 |
#print "Precisions list as Sollya object:", |
910 |
#pobyso_autoprint(truncFormatListSo) |
911 |
pTruncSo = pobyso_round_coefficients_so_so(pStarSo, truncFormatListSo) |
912 |
#print "Truncated polynomial:", ; pobyso_autoprint(pTruncSo) |
913 |
### Compute the error function. This time we consume both the function |
914 |
# and the polynomial. |
915 |
errorFuncSo = sollya_lib_build_function_sub(pTruncSo, |
916 |
funcSo) |
917 |
errorFuncZerosSo = pobyso_dirty_find_zeros_so_so(errorFuncSo, intervalSo) |
918 |
pobyso_clear_obj(pStarSo) |
919 |
#print "Zeroes of the error function for the truncated polynomial from Sollya:" |
920 |
#pobyso_autoprint(errorFuncZerosSo) |
921 |
errorFuncTruncZerosSa = pobyso_float_list_so_sa(errorFuncZerosSo) |
922 |
pobyso_clear_obj(errorFuncZerosSo) |
923 |
## Sollya objects clean up. |
924 |
pobyso_clear_obj(intervalSo) |
925 |
errorFuncZerosSa += errorFuncTruncZerosSa |
926 |
errorFuncZerosSa.sort() |
927 |
## If required, convert the numbers to rational numbers. |
928 |
if not contFracMaxErr is None: |
929 |
for index in xrange(0, len(errorFuncZerosSa)): |
930 |
errorFuncZerosSa[index] = \ |
931 |
errorFuncZerosSa[index].nearby_rational(contFracMaxErr) |
932 |
return errorFuncZerosSa |
933 |
# |
934 |
# End remez_all_poly_error_func_zeros |
935 |
# |
936 |
def cvp_remez_poly_error_func_zeros(funct, |
937 |
maxDegree, |
938 |
lowerBound, |
939 |
upperBound, |
940 |
realField = None, |
941 |
contFracMaxErr = None): |
942 |
""" |
943 |
For a given function f, a degree and an interval, compute the |
944 |
zeros of the (f-remez_d(f)) function. |
945 |
""" |
946 |
## If no realField argument is given try to retrieve it from the |
947 |
# bounds. If impossible (e.g. rational bound), fall back on RR. |
948 |
if realField is None: |
949 |
try: |
950 |
### Force failure if parent does not have prec() member. |
951 |
lowerBound.parent().prec() |
952 |
### If no exception is thrown, set realField. |
953 |
realField = lowerBound.parent() |
954 |
except: |
955 |
realField = RR |
956 |
#print "Real field:", realField |
957 |
funcSa = func |
958 |
funcAsStringSa = func._assume_str().replace("_SAGE_VAR_","",100) |
959 |
#print "Function as a string:", funcAsStringSa |
960 |
## Create the Sollya version of the function and compute the |
961 |
# Remez approximant |
962 |
funcSo = pobyso_parse_string(funcAsStringSa) |
963 |
pStarSo = pobyso_remez_canonical_sa_so(funcAsStringSa, |
964 |
maxDegree, |
965 |
lowerBound, |
966 |
upperBound) |
967 |
## Compute the zeroes of the error function. |
968 |
### Error function creation consumes both pStarSo and funcSo. |
969 |
errorFuncSo = sollya_lib_build_function_sub(pStarSo, funcSo) |
970 |
intervalSo = pobyso_range_from_bounds_sa_so(lowerBound, upperBound) |
971 |
errorFuncZerosSo = pobyso_dirty_find_zeros_so_so(errorFuncSo, intervalSo) |
972 |
pobyso_clear_obj(errorFuncSo) # Clears funcSo and pStarSo as well. |
973 |
#print "Zeroes of the error function from Sollya:" |
974 |
#pobyso_autoprint(errorFuncZerosSo) |
975 |
errorFuncZerosSa = pobyso_float_list_so_sa(errorFuncZerosSo) |
976 |
pobyso_clear_obj(errorFuncZerosSo) |
977 |
## Sollya objects clean up. |
978 |
pobyso_clear_obj(intervalSo) |
979 |
## Converting to rational numbers, if required. |
980 |
if not contFracMaxErr is None: |
981 |
for index in xrange(0, len(errorFuncZerosSa)): |
982 |
errorFuncZerosSa[index] = \ |
983 |
errorFuncZerosSa[index].nearby_rational(contFracMaxErr) |
984 |
return errorFuncZerosSa |
985 |
# |
986 |
# End remez_poly_error_func_zeros |
987 |
# |
988 |
def cvp_round_to_bits(num, numBits): |
989 |
""" |
990 |
Round "num" to "numBits" bits. |
991 |
@param num : the number to round; |
992 |
@param numBits: the number of bits to round to. |
993 |
""" |
994 |
if num == 0: |
995 |
return num |
996 |
log2ofNum = 0 |
997 |
numRounded = 0 |
998 |
## Avoid conversion to floating-point if not necessary. |
999 |
try: |
1000 |
log2OfNum = num.abs().log2() |
1001 |
except: |
1002 |
log2OfNum = RR(num).abs().log2() |
1003 |
## Works equally well for num >= 1 and num < 1. |
1004 |
log2OfNum = ceil(log2OfNum) |
1005 |
# print "cvp_round_to_bits - Log2OfNum:", log2OfNum |
1006 |
divMult = log2OfNum - numBits |
1007 |
#print "cvp_round_to_bits - DivMult:", divMult |
1008 |
if divMult != 0: |
1009 |
numRounded = round(num/2^divMult) * 2^divMult |
1010 |
else: |
1011 |
numRounded = num |
1012 |
return numRounded |
1013 |
# End cvp_round_to_bits |
1014 |
# |
1015 |
def cvp_vector_in_basis(vect, basis): |
1016 |
""" |
1017 |
Compute the coordinates of "vect" in "basis" by |
1018 |
solving a linear system. |
1019 |
@param vect the vector we want to compute the coordinates of |
1020 |
in coordinates of the ambient space; |
1021 |
@param basis the basis we want to compute the coordinates in |
1022 |
as a matrix relative to the ambient space. |
1023 |
""" |
1024 |
## Create the variables for the linear equations. |
1025 |
varDeclString = "" |
1026 |
basisIterationsRange = xrange(0, basis.nrows()) |
1027 |
### Building variables declaration string. |
1028 |
for index in basisIterationsRange: |
1029 |
varName = "a" + str(index) |
1030 |
if varDeclString == "": |
1031 |
varDeclString += varName |
1032 |
else: |
1033 |
varDeclString += "," + varName |
1034 |
### Variables declaration |
1035 |
varsList = var(varDeclString) |
1036 |
sage_eval("var('" + varDeclString + "')") |
1037 |
## Create the equations |
1038 |
equationString = "" |
1039 |
equationsList = [] |
1040 |
for vIndex in xrange(0, len(vect)): |
1041 |
equationString = "" |
1042 |
for bIndex in basisIterationsRange: |
1043 |
if equationString != "": |
1044 |
equationString += "+" |
1045 |
equationString += str(varsList[bIndex]) + "*" + str(basis[bIndex,vIndex]) |
1046 |
equationString += " == " + str(vect[vIndex]) |
1047 |
equationsList.append(sage_eval(equationString)) |
1048 |
## Solve the equations system. The solution dictionary is needed |
1049 |
# to recover the values of the solutions. |
1050 |
solutions = solve(equationsList,varsList, solution_dict=True) |
1051 |
## This code is deactivated: did not solve the problem. |
1052 |
""" |
1053 |
if len(solutions) == 0: |
1054 |
print "Trying Maxima to_poly_sove." |
1055 |
solutions = solve(equationsList,varsList, solution_dict=True, to_poly_solve = 'force') |
1056 |
""" |
1057 |
#print "Solutions:", s |
1058 |
## Recover solutions in rational components vector. |
1059 |
vectInBasis = vector(QQ, basis.nrows()) |
1060 |
### There can be several solution, in the general case. |
1061 |
# Here, there is only one (or none). For each solution, each |
1062 |
# variable has to be searched for. |
1063 |
for sol in solutions: |
1064 |
for bIndex in basisIterationsRange: |
1065 |
vectInBasis[bIndex] = sol[varsList[bIndex]] |
1066 |
return vectInBasis |
1067 |
# End cpv_vector_in_basis. |
1068 |
# |
1069 |
sys.stderr.write("... functions for CVP loaded.\n") |