cvp / src / functions_for_cvp.sage @ a0725e69
Historique | Voir | Annoter | Télécharger (47,52 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_filter_out_undefined_image(initialPointList, func): |
525 |
""" |
526 |
Fom the initial list and function, built a list of points which have a |
527 |
defined image. |
528 |
""" |
529 |
finalPointsList = [] |
530 |
for iterPoint in initialPointList: |
531 |
try: |
532 |
finalPointsList.append(func(iterPoint)) |
533 |
#print "cfoui - Point", iterPoint, "done." |
534 |
except ValueError: |
535 |
pass |
536 |
#print "cfoui - Point", iterPoint, "failed." |
537 |
return finalPointsList |
538 |
# End cvp_filter_out_undefined_image |
539 |
|
540 |
def cvp_float_basis(monomialsList, pointsList, realField): |
541 |
""" |
542 |
For a given monomials list and points list, compute the floating-point |
543 |
basis matrix. |
544 |
""" |
545 |
numRows = len(monomialsList) |
546 |
numCols = len(pointsList) |
547 |
if numRows == 0 or numCols == 0: |
548 |
return matrix(realField, 0, 0) |
549 |
# |
550 |
floatBasis = matrix(realField, numRows, numCols) |
551 |
for rIndex in xrange(0, numRows): |
552 |
for cIndex in xrange(0, numCols): |
553 |
floatBasis[rIndex,cIndex] = \ |
554 |
monomialsList[rIndex](realField(pointsList[cIndex])) |
555 |
return floatBasis |
556 |
# End cvp_float_basis |
557 |
# |
558 |
def cvp_float_vector_for_approx(func, |
559 |
basisPointsList, |
560 |
realField): |
561 |
""" |
562 |
Compute a floating-point vector for the function and the points list. |
563 |
""" |
564 |
# |
565 |
## Some local variables. |
566 |
basisPointsNum = len(basisPointsList) |
567 |
# |
568 |
floatVector = vector(realField, basisPointsNum) |
569 |
## |
570 |
for vIndex in xrange(0,basisPointsNum): |
571 |
### We assume the all for all points their image is defined. |
572 |
floatVector[vIndex] = \ |
573 |
func(basisPointsList[vIndex]) |
574 |
return floatVector |
575 |
# End cvp_float_vector_for_approx. |
576 |
# |
577 |
def cvp_func_abs_max_for_points(func, pointsList, realField): |
578 |
""" |
579 |
Compute the maximum absolute value of a function for a list of |
580 |
points. |
581 |
If several points yield the same value and this value is the maximum, |
582 |
the last visited one is returned. |
583 |
@return (theMaxPoint, theMaxValue) |
584 |
""" |
585 |
evalDict = dict() |
586 |
# |
587 |
## An empty points list is really an error. We cannot return an empty tuple. |
588 |
if len(pointsList) == 0: |
589 |
return None |
590 |
# |
591 |
for pt in pointsList: |
592 |
try: |
593 |
evalDict[abs(realField(func(pt)))] = realField(pt) |
594 |
#print "cfamfp - point:", realField(pt) , "- image:", abs(realField(func(pt))) |
595 |
except ValueError: |
596 |
pass |
597 |
maxAbs = max(evalDict.keys()) |
598 |
#print "cfamfp - maxAbs:", maxAbs, evalDict[maxAbs] |
599 |
return (evalDict[maxAbs], maxAbs) |
600 |
# End cvp_func_abs_max_for_points |
601 |
# |
602 |
def cvp_hkz_reduce(intBasis): |
603 |
""" |
604 |
Thin and simplistic wrapper on the HKZ function of the FP_LLL module. |
605 |
""" |
606 |
fplllIntBasis = FP_LLL(intBasis) |
607 |
fplllIntBasis.HKZ() |
608 |
return fplllIntBasis._sage_() |
609 |
# End cvp_hkz_reduce. |
610 |
# |
611 |
def cvp_int_basis(floatBasis, |
612 |
commonScalingExp, |
613 |
extraScalingExpsList): |
614 |
""" |
615 |
From the float basis, the common scaling factor and the extra exponents |
616 |
compute the integral basis. |
617 |
""" |
618 |
## Checking arguments. |
619 |
if floatBasis.nrows() != len(extraScalingExpsList): |
620 |
return None |
621 |
intBasis = matrix(ZZ, floatBasis.nrows(), floatBasis.ncols()) |
622 |
for rIndex in xrange(0, floatBasis.nrows()): |
623 |
for cIndex in xrange(0, floatBasis.ncols()): |
624 |
intBasis[rIndex, cIndex] = \ |
625 |
(floatBasis[rIndex, cIndex] * \ |
626 |
2^(commonScalingExp + extraScalingExpsList[rIndex])).round() |
627 |
return intBasis |
628 |
# End cvp_int_basis. |
629 |
# |
630 |
def cvp_int_vector_for_approx(floatVect, commonScalingExp, extraScalingExp): |
631 |
""" |
632 |
Compute the integral version of the function vector. |
633 |
""" |
634 |
totalScalingFactor = 2^(commonScalingExp + extraScalingExp) |
635 |
intVect = vector(ZZ, len(floatVect)) |
636 |
for index in xrange(0, len(floatVect)): |
637 |
intVect[index] = (floatVect[index] * totalScalingFactor).round() |
638 |
return intVect |
639 |
# End cvp_int_vector_for_approx. |
640 |
# |
641 |
def cvp_lll_reduce(intBasis): |
642 |
""" |
643 |
Thin and simplistic wrapper around the LLL function |
644 |
""" |
645 |
return intBasis.LLL() |
646 |
# End cvp_lll_reduce. |
647 |
# |
648 |
def cvp_monomials_list(exponentsList, varName = None): |
649 |
""" |
650 |
Create a list of monomials corresponding to the given exponentsList. |
651 |
Monomials are defined as functions. |
652 |
""" |
653 |
monomialsList = [] |
654 |
for exponent in exponentsList: |
655 |
if varName is None: |
656 |
monomialsList.append((x^exponent).function(x)) |
657 |
else: |
658 |
monomialsList.append((varName^exponent).function(varName)) |
659 |
return monomialsList |
660 |
# End cvp_monomials_list. |
661 |
# |
662 |
def cvp_polynomial_coeffs_from_vect(cvpVectInBasis, |
663 |
coeffsPrecList, |
664 |
minCoeffsExpList, |
665 |
extraFuncScalingExp): |
666 |
""" |
667 |
Computes polynomial coefficients out of the elements of the CVP vector. |
668 |
@todo |
669 |
Rewrite the code with a single exponentiation, at the very end. |
670 |
""" |
671 |
numElements = len(cvpVectInBasis) |
672 |
## Arguments check. |
673 |
if numElements != len(minCoeffsExpList) or \ |
674 |
numElements != len(coeffsPrecList): |
675 |
return None |
676 |
polynomialCoeffsList = [] |
677 |
for index in xrange(0, numElements): |
678 |
currentCoeff = cvp_round_to_bits(cvpVectInBasis[index], |
679 |
coeffsPrecList[index]) |
680 |
#print "cvp_polynomial_coeffs - current coefficient rounded:", currentCoeff |
681 |
currentCoeff *= 2^(minCoeffsExpList[index]) |
682 |
#print "cvp_polynomial_coeffs - current coefficient scaled :", currentCoeff |
683 |
currentCoeff *= 2^(-coeffsPrecList[index]) |
684 |
#print "cvp_polynomial_coeffs - current coefficient prec corrected :", currentCoeff |
685 |
currentCoeff *= 2^(-extraFuncScalingExp) |
686 |
#print "cvp_polynomial_coeffs - current coefficient extra func scaled :", currentCoeff |
687 |
polynomialCoeffsList.append(currentCoeff) |
688 |
return polynomialCoeffsList |
689 |
# En polynomial_coeffs_from_vect. |
690 |
# |
691 |
def cvp_polynomial_error_func_maxis(funcSa, |
692 |
polySa, |
693 |
lowerBoundSa, |
694 |
upperBoundSa, |
695 |
realField = None, |
696 |
contFracMaxErr = None): |
697 |
""" |
698 |
For a given function, approximation polynomial and interval (given |
699 |
as bounds) compute the maxima of the functSa - polySo on the interval. |
700 |
Also computes the infnorm of the error function. |
701 |
""" |
702 |
## Arguments check. |
703 |
# @todo. |
704 |
## If no realField argument is given try to retrieve it from the |
705 |
# bounds. If impossible (e.g. rational bound), fall back on RR. |
706 |
if realField is None: |
707 |
try: |
708 |
### Force failure if parent does not have prec() member. |
709 |
lowerBound.parent().prec() |
710 |
### If no exception is thrown, set realField. |
711 |
realField = lowerBound.parent() |
712 |
except: |
713 |
realField = RR |
714 |
#print "Real field:", realField |
715 |
## Compute the Sollya version of the function. |
716 |
funcAsStringSa = funcSa._assume_str().replace("_SAGE_VAR_","",100) |
717 |
#print "cpefa:", funcAsStringSa |
718 |
funcSo = pobyso_parse_string(funcAsStringSa) |
719 |
if pobyso_is_error_so_sa(funcSo): |
720 |
pobyso_clear_obj(funcSo) |
721 |
return None |
722 |
#print "cpefa: function conversion OK." |
723 |
## Compute the Sollya version of the polynomial. |
724 |
## The conversion is made from a floating-point coefficients polynomial. |
725 |
try: |
726 |
polySa.base_ring().prec() |
727 |
convFloatPolySa = polySa |
728 |
except: |
729 |
convFloatPolySa = realField[polySa.variables()[0]](polySa) |
730 |
polySo = pobyso_float_poly_sa_so(convFloatPolySa) |
731 |
if pobyso_is_error_so_sa(funcSo): |
732 |
pobyso_clear_obj(funcSo) |
733 |
pobyso_clear_obj(polySo) |
734 |
return None |
735 |
#print "cpefa: polynomial conversion to Sollya OK." |
736 |
## Copy both funcSo and polySo as they are needed later for the infnorm.. |
737 |
errorFuncSo = \ |
738 |
sollya_lib_build_function_sub(sollya_lib_copy_obj(funcSo), |
739 |
sollya_lib_copy_obj(polySo)) |
740 |
if pobyso_is_error_so_sa(errorFuncSo): |
741 |
pobyso_clear_obj(errorFuncSo) |
742 |
return None |
743 |
#print "cpefa: error function in Sollya OK." |
744 |
## Evaluate the error function at both bounds, it may be usefull, if |
745 |
# the error function is monotonous |
746 |
## Lower bound stuff. |
747 |
lowerBoundSo = pobyso_constant_sa_so(lowerBoundSa) |
748 |
if pobyso_is_error_so_sa(lowerBoundSo): |
749 |
pobyso_clear_obj(errorFuncSo) |
750 |
pobyso_clear_obj(lowerBoundSo) |
751 |
return None |
752 |
errFuncAtLbSa = pobyso_evaluate_so_sa(errorFuncSo, lowerBoundSo) |
753 |
pobyso_clear_obj(lowerBoundSo) |
754 |
if errFuncAtLbSa is None: |
755 |
pobyso_clear_obj(errorFuncSo) |
756 |
return None |
757 |
## The result of the evaluation can be an interval. |
758 |
try: |
759 |
errFuncAtLbSa = errFuncAtLbSa.center() |
760 |
except: |
761 |
errFuncAtLbSa = errFuncAtLbSa |
762 |
#print "cpefa: errFuncAtLbSa:", errFuncAtLbSa |
763 |
## Upper bound stuff. |
764 |
upperBoundSo = pobyso_constant_sa_so(upperBoundSa) |
765 |
if pobyso_is_error_so_sa(upperBoundSo): |
766 |
pobyso_clear_obj(errorFuncSo) |
767 |
pobyso_clear_obj(upperBoundSo) |
768 |
return None |
769 |
errFuncAtUbSa = pobyso_evaluate_so_sa(errorFuncSo, upperBoundSo) |
770 |
pobyso_clear_obj(upperBoundSo) |
771 |
if errFuncAtUbSa is None: |
772 |
return None |
773 |
## The result of the evaluation can be an interval. |
774 |
try: |
775 |
errFuncAtUbSa = errFuncAtUbSa.center() |
776 |
except: |
777 |
errFuncAtUbSa = errFuncAtUbSa |
778 |
#print "cpefa: errFuncAtUbSa:", errFuncAtUbSa |
779 |
## Compute the derivative. |
780 |
diffErrorFuncSo = pobyso_diff_so_so(errorFuncSo) |
781 |
pobyso_clear_obj(errorFuncSo) |
782 |
if pobyso_is_error_so_sa(diffErrorFuncSo): |
783 |
pobyso_clear_obj(diffErrorFuncSo) |
784 |
return None |
785 |
#print "cpefa: polynomial conversion to Sollya OK." |
786 |
#print "cpefa: error function derivative in Sollya OK." |
787 |
## Compute the interval. |
788 |
intervalSo = pobyso_range_from_bounds_sa_so(lowerBound, upperBound) |
789 |
if pobyso_is_error_so_sa(intervalSo): |
790 |
pobyso_clear_obj(diffErrorFuncSo) |
791 |
pobyso_clear_obj(intervalSo) |
792 |
return None |
793 |
## Compute the infnorm of the error function. |
794 |
errFuncSupNormSa = pobyso_supnorm_so_sa(polySo, |
795 |
funcSo, |
796 |
intervalSo, |
797 |
realFieldSa = realField) |
798 |
pobyso_clear_obj(polySo) |
799 |
pobyso_clear_obj(funcSo) |
800 |
## Compute the zeros of the derivative. |
801 |
### Give it a first try with dirtyfindzeros but it may |
802 |
# fail. |
803 |
errorFuncMaxisSo = pobyso_dirty_find_zeros_so_so(diffErrorFuncSo, |
804 |
intervalSo) |
805 |
if pobyso_is_error_so_sa(errorFuncMaxisSo): |
806 |
pobyso_clear_obj(diffErrorFuncSo) |
807 |
pobyso_clear_obj(intervalSo) |
808 |
pobyso_clear_obj(errorFuncMaxisSo) |
809 |
return None |
810 |
#print "cpefa: error function maxis in Sollya OK." |
811 |
errorFuncMaxisSa = pobyso_float_list_so_sa(errorFuncMaxisSo) |
812 |
pobyso_clear_obj(errorFuncMaxisSo) |
813 |
#### If the list is empty try the more sophisticated |
814 |
# findzeros. |
815 |
if len(errorFuncMaxisSa) == 0: |
816 |
errorFuncMaxisSo = \ |
817 |
pobyso_find_zeros_so_so(diffErrorFuncSo, |
818 |
intervalSo) |
819 |
if pobyso_is_error_so_sa(errorFuncMaxisSo): |
820 |
pobyso_clear_obj(diffErrorFuncSo) |
821 |
pobyso_clear_obj(intervalSo) |
822 |
pobyso_clear_obj(errorFuncMaxisSo) |
823 |
return None |
824 |
#print "cpefa: error function maxis in Sollya OK." |
825 |
#print "cpefa:", ; pobyso_autoprint(errorFuncMaxisSo) |
826 |
##### The findzeros functions returns intervals (ranges). |
827 |
errorFuncRangeMaxisSa = pobyso_range_list_so_sa(errorFuncMaxisSo) |
828 |
#print "cpefa:", errorFuncRangeMaxisSa |
829 |
pobyso_clear_obj(errorFuncMaxisSo) |
830 |
errorFuncMaxisSa = [] |
831 |
if len(errorFuncRangeMaxisSa) != 0: |
832 |
for interval in errorFuncRangeMaxisSa: |
833 |
errorFuncMaxisSa.append(interval.center()) |
834 |
#print "cpefa:", errorFuncMaxisSa |
835 |
else: # The error function is monotonous. It reaches its maximum |
836 |
# at either of the bounds. |
837 |
errFuncMaxAtBounds = max(abs(errFuncAtLbSa), abs(errFuncAtUbSa)) |
838 |
if errFuncMaxAtBounds == abs(errFuncAtLbSa): |
839 |
errorFuncMaxisSa.append(lowerBoundSa) |
840 |
else: |
841 |
errorFuncMaxisSa.append(upperBoundSa) |
842 |
pobyso_clear_obj(diffErrorFuncSo) |
843 |
pobyso_clear_obj(intervalSo) |
844 |
## If required, convert the numbers to rational numbers. |
845 |
#print "cpefa - errorFuncMaxisSa:", errorFuncMaxisSa |
846 |
if not contFracMaxErr is None: |
847 |
for index in xrange(0, len(errorFuncMaxisSa)): |
848 |
errorFuncMaxisSa[index] = \ |
849 |
errorFuncMaxisSa[index].nearby_rational(contFracMaxErr) |
850 |
return (errorFuncMaxisSa, errFuncSupNormSa) |
851 |
# End cvp_polynomial_error_func_maxis |
852 |
# |
853 |
def cvp_polynomial_from_coeffs_and_exps(coeffsList, |
854 |
expsList, |
855 |
polyField = None, |
856 |
theVar = None): |
857 |
""" |
858 |
Build a polynomial in the classical monomials (possibly lacunary) basis |
859 |
from a list of coefficients and a list of exponents. The polynomial is in |
860 |
the polynomial field given as argument. |
861 |
""" |
862 |
if len(coeffsList) != len(expsList): |
863 |
return None |
864 |
## If no variable is given, "x" is used. |
865 |
## If no polyField is given, we fall back on a polynomial field on RR. |
866 |
if theVar is None: |
867 |
if polyField is None: |
868 |
theVar = x |
869 |
polyField = RR[theVar] |
870 |
else: |
871 |
theVar = var(polyField.variable_name()) |
872 |
else: ### theVar is set. |
873 |
### No polyField, fallback on RR[theVar]. |
874 |
if polyField is None: |
875 |
polyField = RR[theVar] |
876 |
else: ### Both the polyFiled and theVar are set: create a new polyField |
877 |
# with theVar. The original polyField is not affected by the |
878 |
# change. |
879 |
polyField = polyField.change_var(theVar) |
880 |
## Seed the polynomial. |
881 |
poly = polyField(0) |
882 |
## Append the terms. |
883 |
for coeff, exp in zip(coeffsList, expsList): |
884 |
poly += polyField(coeff * theVar^exp) |
885 |
return poly |
886 |
# End cvp_polynomial_from_coeffs_and_exps. |
887 |
# |
888 |
def cvp_remez_all_poly_error_func_maxis(funct, |
889 |
maxDegree, |
890 |
lowerBound, |
891 |
upperBound, |
892 |
precsList, |
893 |
realField = None, |
894 |
contFracMaxErr = None): |
895 |
""" |
896 |
For a given function f, a degree and an interval, compute the |
897 |
maxima of the (f-remez_d(f)) function and those of the (f-truncRemez_d(f)) |
898 |
function over the interval. |
899 |
""" |
900 |
## If no realField argument is given try to retrieve it from the |
901 |
# bounds. If impossible (e.g. rational bound), fall back on RR. |
902 |
if realField is None: |
903 |
try: |
904 |
### Force failure if parent does not have prec() member. |
905 |
lowerBound.parent().prec() |
906 |
### If no exception is thrown, set realField. |
907 |
realField = lowerBound.parent() |
908 |
except: |
909 |
realField = RR |
910 |
#print "Real field:", realField |
911 |
funcSa = func |
912 |
funcAsStringSa = func._assume_str().replace("_SAGE_VAR_","",100) |
913 |
print "Function as a string:", funcAsStringSa |
914 |
## Create the Sollya version of the function and compute the |
915 |
# Remez approximant |
916 |
funcSo = pobyso_parse_string(funcAsStringSa) |
917 |
pStarSo = pobyso_remez_canonical_sa_so(funcAsStringSa, |
918 |
maxDegree, |
919 |
lowerBound, |
920 |
upperBound) |
921 |
## Compute the error function and its derivative |
922 |
### First create the error function with copies since they are needed later. |
923 |
errorFuncSo = sollya_lib_build_function_sub(sollya_lib_copy_obj(pStarSo), |
924 |
sollya_lib_copy_obj(funcSo)) |
925 |
intervalSo = pobyso_range_from_bounds_sa_so(lowerBound, upperBound) |
926 |
diffErrorFuncSo = pobyso_diff_so_so(errorFuncSo) |
927 |
pobyso_clear_obj(errorFuncSo) |
928 |
## Compute the zeros of the derivative. |
929 |
errorFuncMaxisSo = pobyso_dirty_find_zeros_so_so(diffErrorFuncSo, intervalSo) |
930 |
pobyso_clear_obj(diffErrorFuncSo) |
931 |
errorFuncMaxisSa = pobyso_float_list_so_sa(errorFuncMaxisSo) |
932 |
pobyso_clear_obj(errorFuncMaxisSo) |
933 |
## Compute the truncated Remez polynomial and the error function. |
934 |
truncFormatListSo = pobyso_build_list_of_ints_sa_so(*precsList) |
935 |
pTruncSo = pobyso_round_coefficients_so_so(pStarSo, truncFormatListSo) |
936 |
pobyso_clear_obj(pStarSo) |
937 |
### Compute the error function. This time we consume both the function |
938 |
# and the polynomial. |
939 |
errorFuncSo = sollya_lib_build_function_sub(pTruncSo, funcSo) |
940 |
## Compute the derivative. |
941 |
diffErrorFuncSo = pobyso_diff_so_so(errorFuncSo) |
942 |
pobyso_clear_obj(errorFuncSo) |
943 |
## Compute the zeros of the derivative. |
944 |
errorFuncMaxisSo = pobyso_dirty_find_zeros_so_so(diffErrorFuncSo, intervalSo) |
945 |
pobyso_clear_obj(diffErrorFuncSo) |
946 |
pobyso_clear_obj(intervalSo) |
947 |
errorFuncTruncMaxisSa = pobyso_float_list_so_sa(errorFuncMaxisSo) |
948 |
pobyso_clear_obj(errorFuncMaxisSo) |
949 |
## Merge with the first list, removing duplicates if any. |
950 |
errorFuncMaxisSa.extend(elem for elem in errorFuncTruncMaxisSa \ |
951 |
if elem not in errorFuncMaxisSa) |
952 |
errorFuncMaxisSa.sort() |
953 |
## If required, convert the numbers to rational numbers. |
954 |
if not contFracMaxErr is None: |
955 |
for index in xrange(0, len(errorFuncMaxisSa)): |
956 |
errorFuncMaxisSa[index] = \ |
957 |
errorFuncMaxisSa[index].nearby_rational(contFracMaxErr) |
958 |
return errorFuncMaxisSa |
959 |
# End cvp_remez_all_poly_error_func_maxis. |
960 |
# |
961 |
def cvp_remez_all_poly_error_func_zeros(funct, |
962 |
maxDegree, |
963 |
lowerBound, |
964 |
upperBound, |
965 |
precsList, |
966 |
realField = None, |
967 |
contFracMaxErr = None): |
968 |
""" |
969 |
For a given function f, a degree and an interval, compute the |
970 |
zeros of the (f-remez_d(f)) function and those of the (f-truncRemez_d(f)) |
971 |
function over the interval. |
972 |
""" |
973 |
## If no realField argument is given try to retrieve it from the |
974 |
# bounds. If impossible (e.g. rational bound), fall back on RR. |
975 |
if realField is None: |
976 |
try: |
977 |
### Force failure if parent does not have prec() member. |
978 |
lowerBound.parent().prec() |
979 |
### If no exception is thrown, set realField. |
980 |
realField = lowerBound.parent() |
981 |
except: |
982 |
realField = RR |
983 |
#print "Real field:", realField |
984 |
funcSa = func |
985 |
funcAsStringSa = func._assume_str().replace("_SAGE_VAR_","",100) |
986 |
print "Function as a string:", funcAsStringSa |
987 |
## Create the Sollya version of the function and compute the |
988 |
# Remez approximant |
989 |
funcSo = pobyso_parse_string(funcAsStringSa) |
990 |
pStarSo = pobyso_remez_canonical_sa_so(funcAsStringSa, |
991 |
maxDegree, |
992 |
lowerBound, |
993 |
upperBound) |
994 |
## Compute the zeroes of the error function. |
995 |
### First create the error function with copies since they are needed later. |
996 |
errorFuncSo = sollya_lib_build_function_sub(sollya_lib_copy_obj(pStarSo), |
997 |
sollya_lib_copy_obj(funcSo)) |
998 |
intervalSo = pobyso_range_from_bounds_sa_so(lowerBound, upperBound) |
999 |
errorFuncZerosSo = pobyso_dirty_find_zeros_so_so(errorFuncSo, intervalSo) |
1000 |
pobyso_clear_obj(errorFuncSo) # Clears funcSo and pStarSo as well. |
1001 |
#print "Zeroes of the error function from Sollya:" |
1002 |
#pobyso_autoprint(errorFuncZerosSo) |
1003 |
errorFuncZerosSa = pobyso_float_list_so_sa(errorFuncZerosSo) |
1004 |
pobyso_clear_obj(errorFuncZerosSo) |
1005 |
#print "\nZeroes of the error function from Sage:" |
1006 |
#print errorFuncZerosSa |
1007 |
# |
1008 |
## Deal with the truncated polynomial now. |
1009 |
### Create the formats list. Notice the "*" before the list variable name. |
1010 |
truncFormatListSo = pobyso_build_list_of_ints_sa_so(*precsList) |
1011 |
#print "Precisions list as Sollya object:", |
1012 |
#pobyso_autoprint(truncFormatListSo) |
1013 |
pTruncSo = pobyso_round_coefficients_so_so(pStarSo, truncFormatListSo) |
1014 |
#print "Truncated polynomial:", ; pobyso_autoprint(pTruncSo) |
1015 |
### Compute the error function. This time we consume both the function |
1016 |
# and the polynomial. |
1017 |
errorFuncSo = sollya_lib_build_function_sub(pTruncSo, |
1018 |
funcSo) |
1019 |
errorFuncZerosSo = pobyso_dirty_find_zeros_so_so(errorFuncSo, intervalSo) |
1020 |
pobyso_clear_obj(pStarSo) |
1021 |
#print "Zeroes of the error function for the truncated polynomial from Sollya:" |
1022 |
#pobyso_autoprint(errorFuncZerosSo) |
1023 |
errorFuncTruncZerosSa = pobyso_float_list_so_sa(errorFuncZerosSo) |
1024 |
pobyso_clear_obj(errorFuncZerosSo) |
1025 |
## Sollya objects clean up. |
1026 |
pobyso_clear_obj(intervalSo) |
1027 |
errorFuncZerosSa += errorFuncTruncZerosSa |
1028 |
errorFuncZerosSa.sort() |
1029 |
## If required, convert the numbers to rational numbers. |
1030 |
if not contFracMaxErr is None: |
1031 |
for index in xrange(0, len(errorFuncZerosSa)): |
1032 |
errorFuncZerosSa[index] = \ |
1033 |
errorFuncZerosSa[index].nearby_rational(contFracMaxErr) |
1034 |
return errorFuncZerosSa |
1035 |
# |
1036 |
# End remez_all_poly_error_func_zeros |
1037 |
# |
1038 |
def cvp_remez_poly_error_func_zeros(funct, |
1039 |
maxDegree, |
1040 |
lowerBound, |
1041 |
upperBound, |
1042 |
realField = None, |
1043 |
contFracMaxErr = None): |
1044 |
""" |
1045 |
For a given function f, a degree and an interval, compute the |
1046 |
zeros of the (f-remez_d(f)) function. |
1047 |
""" |
1048 |
## If no realField argument is given try to retrieve it from the |
1049 |
# bounds. If impossible (e.g. rational bound), fall back on RR. |
1050 |
if realField is None: |
1051 |
try: |
1052 |
### Force failure if parent does not have prec() member. |
1053 |
lowerBound.parent().prec() |
1054 |
### If no exception is thrown, set realField. |
1055 |
realField = lowerBound.parent() |
1056 |
except: |
1057 |
realField = RR |
1058 |
#print "Real field:", realField |
1059 |
funcSa = func |
1060 |
funcAsStringSa = func._assume_str().replace("_SAGE_VAR_","",100) |
1061 |
#print "Function as a string:", funcAsStringSa |
1062 |
## Create the Sollya version of the function and compute the |
1063 |
# Remez approximant |
1064 |
funcSo = pobyso_parse_string(funcAsStringSa) |
1065 |
pStarSo = pobyso_remez_canonical_sa_so(funcAsStringSa, |
1066 |
maxDegree, |
1067 |
lowerBound, |
1068 |
upperBound) |
1069 |
## Compute the zeroes of the error function. |
1070 |
### Error function creation consumes both pStarSo and funcSo. |
1071 |
errorFuncSo = sollya_lib_build_function_sub(pStarSo, funcSo) |
1072 |
intervalSo = pobyso_range_from_bounds_sa_so(lowerBound, upperBound) |
1073 |
errorFuncZerosSo = pobyso_dirty_find_zeros_so_so(errorFuncSo, intervalSo) |
1074 |
pobyso_clear_obj(errorFuncSo) # Clears funcSo and pStarSo as well. |
1075 |
#print "Zeroes of the error function from Sollya:" |
1076 |
#pobyso_autoprint(errorFuncZerosSo) |
1077 |
errorFuncZerosSa = pobyso_float_list_so_sa(errorFuncZerosSo) |
1078 |
pobyso_clear_obj(errorFuncZerosSo) |
1079 |
## Sollya objects clean up. |
1080 |
pobyso_clear_obj(intervalSo) |
1081 |
## Converting to rational numbers, if required. |
1082 |
if not contFracMaxErr is None: |
1083 |
for index in xrange(0, len(errorFuncZerosSa)): |
1084 |
errorFuncZerosSa[index] = \ |
1085 |
errorFuncZerosSa[index].nearby_rational(contFracMaxErr) |
1086 |
return errorFuncZerosSa |
1087 |
# |
1088 |
# End remez_poly_error_func_zeros |
1089 |
# |
1090 |
def cvp_round_to_bits(num, numBits): |
1091 |
""" |
1092 |
Round "num" to "numBits" bits. |
1093 |
@param num : the number to round; |
1094 |
@param numBits: the number of bits to round to. |
1095 |
""" |
1096 |
if num == 0: |
1097 |
return num |
1098 |
log2ofNum = 0 |
1099 |
numRounded = 0 |
1100 |
## Avoid conversion to floating-point if not necessary. |
1101 |
try: |
1102 |
log2OfNum = num.abs().log2() |
1103 |
except: |
1104 |
log2OfNum = RR(num).abs().log2() |
1105 |
## Works equally well for num >= 1 and num < 1. |
1106 |
log2OfNum = ceil(log2OfNum) |
1107 |
# print "cvp_round_to_bits - Log2OfNum:", log2OfNum |
1108 |
divMult = log2OfNum - numBits |
1109 |
#print "cvp_round_to_bits - DivMult:", divMult |
1110 |
if divMult != 0: |
1111 |
numRounded = round(num/2^divMult) * 2^divMult |
1112 |
else: |
1113 |
numRounded = num |
1114 |
return numRounded |
1115 |
# End cvp_round_to_bits |
1116 |
# |
1117 |
def cvp_vector_in_basis(vect, basis): |
1118 |
""" |
1119 |
Compute the coordinates of "vect" in "basis" by |
1120 |
solving a linear system. |
1121 |
@param vect the vector we want to compute the coordinates of |
1122 |
in coordinates of the ambient space; |
1123 |
@param basis the basis we want to compute the coordinates in |
1124 |
as a matrix relative to the ambient space. |
1125 |
""" |
1126 |
## Create the variables for the linear equations. |
1127 |
varDeclString = "" |
1128 |
basisIterationsRange = xrange(0, basis.nrows()) |
1129 |
### Building variables declaration string. |
1130 |
for index in basisIterationsRange: |
1131 |
varName = "a" + str(index) |
1132 |
if varDeclString == "": |
1133 |
varDeclString += varName |
1134 |
else: |
1135 |
varDeclString += "," + varName |
1136 |
### Variables declaration |
1137 |
varsList = var(varDeclString) |
1138 |
sage_eval("var('" + varDeclString + "')") |
1139 |
## Create the equations |
1140 |
equationString = "" |
1141 |
equationsList = [] |
1142 |
for vIndex in xrange(0, len(vect)): |
1143 |
equationString = "" |
1144 |
for bIndex in basisIterationsRange: |
1145 |
if equationString != "": |
1146 |
equationString += "+" |
1147 |
equationString += str(varsList[bIndex]) + "*" + str(basis[bIndex,vIndex]) |
1148 |
equationString += " == " + str(vect[vIndex]) |
1149 |
equationsList.append(sage_eval(equationString)) |
1150 |
## Solve the equations system. The solution dictionary is needed |
1151 |
# to recover the values of the solutions. |
1152 |
solutions = solve(equationsList,varsList, solution_dict=True) |
1153 |
## This code is deactivated: did not solve the problem. |
1154 |
""" |
1155 |
if len(solutions) == 0: |
1156 |
print "Trying Maxima to_poly_sove." |
1157 |
solutions = solve(equationsList,varsList, solution_dict=True, to_poly_solve = 'force') |
1158 |
""" |
1159 |
#print "Solutions:", s |
1160 |
## Recover solutions in rational components vector. |
1161 |
vectInBasis = vector(QQ, basis.nrows()) |
1162 |
### There can be several solution, in the general case. |
1163 |
# Here, there is only one (or none). For each solution, each |
1164 |
# variable has to be searched for. |
1165 |
for sol in solutions: |
1166 |
for bIndex in basisIterationsRange: |
1167 |
vectInBasis[bIndex] = sol[varsList[bIndex]] |
1168 |
return vectInBasis |
1169 |
# End cpv_vector_in_basis. |
1170 |
# |
1171 |
sys.stderr.write("... functions for CVP loaded.\n") |