Statistiques
| Branche: | Révision :

cvp / src / functions_for_cvp.sage @ 9b0c03e7

Historique | Voir | Annoter | Télécharger (27,56 ko)

1
"""@package functions_for_cvp
2
Auxiliary functions used for CVP.
3
"""
4
print "Functions for CVP loading..."
5
#
6
def cvp_affine_from_chebyshev(lowerBound, upperBound):
7
    """
8
    Compute the affine parameters to map [-1, 1] to the interval given
9
    as argument.
10
    @param lowerBound (of the target interval)
11
    @param upperBound (of the target interval)
12
    @return the (scalingCoefficient, offset) tuple.
13
    """
14
    ## Check bounds consistency. Bounds must differ.
15
    if lowerBound >= upperBound:
16
        return None
17
    scalingCoefficient = (upperBound - lowerBound) / 2
18
    offset             = (lowerBound + upperBound) / 2
19
    return (scalingCoefficient, offset)
20
# End cvp_affine_from_chebyshev
21
#
22
def cvp_affine_to_chebyshev(lowerBound, upperBound):
23
    """
24
    Compute the affine parameters to map the interval given
25
    as argument to  [-1, 1].
26
    @param lowerBound (of the target interval)
27
    @param upperBound (of the target interval)
28
    @return the (scalingCoefficient, offset) tuple.
29
    """
30
    ## Check bounds consistency. Bounds must differ.
31
    if lowerBound >= upperBound:
32
        return None
33
    scalingCoefficient = 2 / (upperBound - lowerBound)
34
    ## If bounds are symmetrical with relation to 0, return 0 straight before
35
    #  attempting a division by 0.
36
    if lowerBound == -upperBound:
37
        offset         = 0
38
    else:
39
        offset         =  (lowerBound + upperBound) / (lowerBound - upperBound)
40
    return (scalingCoefficient, offset)
41
# End cvp_affine_to_chebyshev
42
#
43
def cvp_babai(redBasis, redBasisGso, vect):
44
    """
45
    Closest plane vector implementation as per Babaï.
46
    @param redBasis   : a lattice basis, preferably a reduced one; 
47
    @param redBasisGSO: the GSO of the previous basis;
48
    @param vector     : a vector, in coordinated in the ambient 
49
                        space of the lattice
50
    @return the closest vector to the input, in coordinates in the 
51
                        ambient space of the lattice.
52
    """
53
    ## A deep copy is not necessary here.
54
    curVect = copy(vect)
55
    print "cvp_babai - Vector:", vect
56
    ## From index of last row down to 0.
57
    for vIndex in xrange(len(redBasis.rows())-1, -1, -1):
58
        curRBGSO = redBasisGso.row(vIndex)
59
        curVect = curVect - \
60
                  (round((curVect * curRBGSO)  / (curRBGSO * curRBGSO)) * \
61
                   redBasis.row(vIndex)) 
62
    return vect - curVect
63
# End cvp_babai
64
#
65
def cvp_bkz_reduce(intBasis, blockSize):
66
    """
67
    Thin and simplistic wrapper the HKZ function of the FP_LLL module.
68
    """
69
    fplllIntBasis = FP_LLL(intBasis)
70
    fplllIntBasis.BKZ(blockSize)
71
    return fplllIntBasis._sage_()
72
# End cvp_hkz_reduce.
73
#
74
def cvp_coefficients_bounds_projection(executablePath, arguments):
75
    """
76
    Compute the min and max of the coefficients with linear
77
    programming projection.
78
    @param executablePath: the path to the binary program;
79
    @param arguments: a list of arguments to be givent to the binary
80
    @return: the min and max coefficients value arrays (in this order).
81
    """
82
    from subprocess import check_output
83
    commandLine = [executablePath] + arguments
84
    ## Get rid of output on stderr.
85
    devNull = open("/dev/null", "rw")
86
    ## Run ther program.
87
    otp = check_output(commandLine, stderr=devNull)
88
    devNull.close()
89
    ## Recover the results
90
    bounds = sage_eval(otp)
91
    minCoeffsExpList = []
92
    maxCoeffsExpList = [] 
93
    #print "bounds:", bounds
94
    for boundsPair in bounds:
95
        minCoeffsExpList.append(boundsPair[0])
96
        maxCoeffsExpList.append(boundsPair[1])
97
    print "minCoeffsExpList:", minCoeffsExpList
98
    print "maxCoeffsExpList:", maxCoeffsExpList
99
    return (minCoeffsExpList, maxCoeffsExpList)
100
# End cvp_coefficients_bounds_projection
101

    
102
def cvp_coefficients_bounds_projection_exps(executablePath, 
103
                                            arguments, 
104
                                            realField = None):
105
    """
106
    Compute the min and max exponents of the coefficients with linear
107
    programming projection.
108
    @param executablePath: the path to the binary program;
109
    @param arguments: a list of arguments to be givent to the binary
110
    @param realField: the realField to use for floating-point conversion.
111
    @return: the min and max exponents arrays (in this order).
112
    """
113
    ## If no realField is givne, fall back on RR.
114
    if realField is None:
115
        realField = RR
116
    (minCoeffsExpList, maxCoeffsExpList) = \
117
        cvp_coefficients_bounds_projection(executablePath,arguments)
118
    for index in xrange(0, len(minCoeffsExpList)):
119
        minCoeffsExpList[index] = \
120
            realField(minCoeffsExpList[index]).abs().log2().floor()
121
        maxCoeffsExpList[index] = \
122
            realField(maxCoeffsExpList[index]).abs().log2().floor()
123
    return (minCoeffsExpList, maxCoeffsExpList)
124
# End cvp_coefficients_bounds_projection_exps
125

    
126
def cvp_chebyshev_zeros_1k(numPoints, realField, contFracMaxErr = None):
127
    """
128
    Compute the Chebyshev zeros for some polynomial degree (numPoints, for the
129
    zeros) scaled to the [lowerBound, upperBound] interval.
130
    The list is returned as row floating-point numbers is contFracMaxErr is None.
131
    Otherwise elements are transformed into rational numbers. 
132
    """
133
    if numPoints < 1:
134
        return None
135
    if numPoints == 0:
136
        return [0]
137
    ## Check that realField has a "prec()" member.
138
    try:
139
        realField.prec()
140
    except:
141
        return None
142
    #
143
    zerosList = []
144
    ## formulas: cos (((2*i - 1) * pi) / (2*numPoints)) for i = 1,...,numPoints.
145
    #  If i is -1-shifted, as in the following loop, formula is 
146
    #  cos (((2*i + 1) * pi) / (2*numPoints)) for i = 0,...,numPoints-1.
147
    for index in xrange(0, numPoints):
148
        ## When number of points is odd (then, the Chebyshev degree is odd two), 
149
        #  the central point is 0. */
150
        if (numPoints % 2 == 1) and ((2 * index + 1) == numPoints):
151
            if contFracMaxErr is None:
152
                zerosList.append(realField(0))
153
            else:
154
                zerosList.append(0)
155
        else:
156
            currentCheby = \
157
                ((realField(2*index+1) * realField(pi)) / 
158
                 realField(2*numPoints)).cos()
159
            #print  "Current Cheby:", currentCheby
160
            ## Result is negated to have an increasing order list.
161
            if contFracMaxErr is None:
162
                zerosList.append(-currentCheby)
163
            else:
164
                zerosList.append(-currentCheby.nearby_rational(contFracMaxErr))
165
            #print "Relative error:", (currentCheby/zerosList[index])
166
    return zerosList
167
# End cvp_chebyshev_zeros_1k.
168
#
169
def cvp_chebyshev_zeros_for_interval(lowerBound, 
170
                                     upperBound, 
171
                                     numPoints,
172
                                     realField = None, 
173
                                     contFracMaxErr = None):
174
    """
175
    Compute the Chebyshev zeros for some polynomial degree (numPoints, for the
176
    zeros) scaled to the [lowerBound, upperBound] interval.
177
    If no contFracMaxErr argument is given, we return the list as "raw"
178
    floating-points. Otherwise, rational numbers are returned.
179
    """
180
    ## Arguments check.
181
    if lowerBound >= upperBound:
182
        return None
183
    if numPoints < 1:
184
        return None
185
    ## If no realField argument is given try to retrieve it from the 
186
    #  bounds. If impossible (e.g. rational bound), fall back on RR. 
187
    if realField is None:
188
        try:
189
            ### Force failure if parent does not have prec() member.
190
            lowerBound.parent().prec()
191
            ### If no exception is thrown, set realField.
192
            realField = lowerBound.parent()
193
        except:
194
            realField = RR
195
    #print "Real field:", realField
196
    ## We want "raw"floating-point nodes to only have one final rounding.
197
    chebyshevZerosList = \
198
        cvp_chebyshev_zeros_1k(numPoints, realField)
199
    scalingFactor, offset = cvp_affine_from_chebyshev(lowerBound, upperBound)
200
    for index in xrange(0, len(chebyshevZerosList)):
201
        chebyshevZerosList[index] = \
202
            chebyshevZerosList[index] * scalingFactor + offset
203
        if not contFracMaxErr is None:
204
            chebyshevZerosList[index] = \
205
                chebyshevZerosList[index].nearby_rational(contFracMaxErr)
206
    return chebyshevZerosList                                                             
207
# End cvp_chebyshev_zeros_for_interval.
208
#
209
def cvp_common_scaling_exp(precision, 
210
                           precisionFraction = None):
211
    """
212
    Compute the common scaling factor (a power of 2).
213
    The exponent is a fraction of the precision;
214
    A extra factor is computed for the vector,
215
    exra factors are computed for the basis vectors, all in the corresponding
216
    functions.
217
    """
218
    ## Set a default value for the precisionFraction to 1/2.
219
    if precisionFraction is None:
220
        precisionFraction = 3/4
221
    """
222
    minBasisVectsNorm = oo
223
    currentNorm = 0
224
    for vect in floatBasis.rows():
225
        currentNorm = vect.norm()
226
        print "Current norm:", currentNorm
227
        if currentNorm < minBasisVectsNorm:
228
            minBasisVectsNorm = currentNorm
229
    currentNorm = funcVect.norm()
230
    print "Current norm:", currentNorm
231
    if currentNorm < minBasisVectsNorm:
232
        minBasisVectsNorm = currentNorm
233
    ## Check if a push is need because the smallest norm is below 0.    
234
    powerForMinNorm = floor(log(minBasisVectsNorm)/log2)
235
    print "Power for min norm :", powerForMinNorm
236
    print "Power for precision:", ceil(precision*precisionFraction)
237
    if powerForMinNorm < 0:
238
        return 2^(ceil(precision*precisionFraction) - powerFromMinNorm)
239
    else:
240
    """
241
    return ceil(precision * precisionFraction)
242
# End cvp_common_scaling_factor.
243
#
244
def cvp_evaluation_points_list(funct, 
245
                               maxDegree, 
246
                               lowerBound, 
247
                               upperBound, 
248
                               realField = None):
249
    """
250
    Compute a list of points for the vector creation.
251
    Strategy:
252
    - compute the zeros of the function-remez;
253
    - compute the zeros of the function-rounded_remez;
254
    - compute the Chebyshev points.
255
    Merge the whole thing.
256
    """
257
    
258
# End cvp_evaluation_points_list.
259
#
260
def cvp_extra_basis_scaling_exps(precsList, minExponentsList):
261
    extraScalingExpsList = []
262
    for minExp, prec in zip(minExponentsList, precsList):
263
        if minExp - prec < 0:
264
            extraScalingExpsList.append(minExp - prec)
265
        else:
266
            extraScalingExpsList.append(0)
267
    return extraScalingExpsList
268
# End cvp_extra_basis_scaling_exps.
269
#
270
def cvp_extra_function_scaling_exp(floatBasis,
271
                                   floatFuncVect,
272
                                   maxExponentsList):
273
    """
274
    Compute the extra scaling exponent for the function vector in ordre to 
275
    guarantee that the maximum exponent can be reached for each element of the
276
    basis.
277
    """
278
    ## Check arguments
279
    if floatBasis.nrows() == 0 or \
280
       floatBasis.ncols() == 0 or \
281
       len(floatFuncVect)      == 0:
282
        return 1
283
    if len(maxExponentsList) != floatBasis.nrows():
284
        return None
285
    ## Compute the log of the norm of the function vector.
286
    funcVectNormLog  = log(floatFuncVect.norm())
287
    ## Compute the extra scaling factor for each vector of the basis.
288
    #  for norms ratios an maxExponentsList. 
289
    extraScalingExp = 0
290
    for (row, maxExp) in zip(floatBasis.rows(),maxExponentsList):
291
        rowNormLog     = log(row.norm())
292
        normsRatioLog2 = floor((funcVectNormLog - rowNormLog) / log2) 
293
        #print "Current norms ratio log2:", normsRatioLog2
294
        scalingExpCandidate = normsRatioLog2 - maxExp 
295
        #print "Current scaling exponent candidate:", scalingExpCandidate
296
        if scalingExpCandidate < 0:
297
            if -scalingExpCandidate > extraScalingExp:
298
                extraScalingExp = -scalingExpCandidate
299
    return extraScalingExp
300
# End cvp_extra_function_scaling_exp.
301
#
302
def cvp_float_basis(monomialsList, pointsList, realField):
303
    """
304
    For a given monomials list and points list, compute the floating-point
305
    basis matrix.
306
    """
307
    numRows    = len(monomialsList)
308
    numCols    = len(pointsList)
309
    if numRows == 0 or numCols == 0:
310
        return matrix(realField, 0, 0)
311
    #
312
    floatBasis = matrix(realField, numRows, numCols)
313
    for rIndex in xrange(0, numRows):
314
        for cIndex in xrange(0, numCols):
315
            floatBasis[rIndex,cIndex] = \
316
                monomialsList[rIndex](realField(pointsList[cIndex]))
317
    return floatBasis
318
# End cvp_float_basis
319
#
320
def cvp_float_vector_for_approx(func, 
321
                                basisPointsList,
322
                                realField):
323
    """
324
    Compute a floating-point vector for the function and the points list.
325
    """
326
    #
327
    ## Some local variables.
328
    basisPointsNum = len(basisPointsList)
329
    #
330
    ##
331
    vVect = vector(realField, basisPointsNum)
332
    for vIndex in xrange(0,basisPointsNum):
333
        vVect[vIndex] = \
334
            func(basisPointsList[vIndex])
335
    return vVect
336
# End cvp_float_vector_for_approx.
337
#
338
def cvp_hkz_reduce(intBasis):
339
    """
340
    Thin and simplistic wrapper the HKZ function of the FP_LLL module.
341
    """
342
    fplllIntBasis = FP_LLL(intBasis)
343
    fplllIntBasis.HKZ()
344
    return fplllIntBasis._sage_()
345
# End cvp_hkz_reduce.
346
#
347
def cvp_int_basis(floatBasis, 
348
                  commonScalingExp, 
349
                  extraScalingExpsList):
350
    """
351
    From the float basis, the common scaling factor and the extra exponents 
352
    compute the integral basis.
353
    """
354
    ## Checking arguments.
355
    if floatBasis.nrows() != len(extraScalingExpsList):
356
        return None
357
    intBasis = matrix(ZZ, floatBasis.nrows(), floatBasis.ncols())
358
    for rIndex in xrange(0, floatBasis.nrows()):
359
        for cIndex in xrange(0, floatBasis.ncols()):
360
            intBasis[rIndex, cIndex] = \
361
            (floatBasis[rIndex, cIndex] * \
362
            2^(commonScalingExp + extraScalingExpsList[rIndex])).round()
363
    return intBasis
364
# End cvp_int_basis.
365
#
366
def cvp_int_vector_for_approx(floatVect, commonScalingExp, extraScalingExp):
367
    """
368
    Compute the integral version of the function vector.
369
    """
370
    totalScalingFactor = 2^(commonScalingExp + extraScalingExp)
371
    intVect = vector(ZZ, len(floatVect))
372
    for index in xrange(0, len(floatVect)):
373
        intVect[index] = (floatVect[index] * totalScalingFactor).round()
374
    return intVect
375
# End cvp_int_vector_for_approx.
376
#
377
def cvp_lll_reduce(intBasis):
378
    """
379
    Thin and simplistic wrapper around the LLL function
380
    """
381
    return intBasis.LLL()
382
# End cvp_lll_reduce.
383
#
384
def cvp_monomials_list(exponentsList, varName = None):
385
    """
386
    Create a list of monomials corresponding to the given exponentsList.
387
    Monomials are defined as functions.
388
    """
389
    monomialsList = []
390
    for exponent in exponentsList:
391
        if varName is None:
392
            monomialsList.append((x^exponent).function(x))
393
        else:
394
            monomialsList.append((varName^exponent).function(varName))
395
    return monomialsList
396
# End cvp_monomials_list.
397
#
398
def cvp_polynomial_coeffs_from_vect(cvpVectInBasis,
399
                                   coeffsPrecList, 
400
                                   minCoeffsExpList,
401
                                   extraFuncScalingExp):
402
    numElements = len(cvpVectInBasis)
403
    ## Arguments check.
404
    if numElements != len(minCoeffsExpList) or \
405
       numElements != len(coeffsPrecList):
406
        return None
407
    polynomialCoeffsList = []
408
    for index in xrange(0, numElements):
409
        currentCoeff = cvp_round_to_bits(cvpVectInBasis[index],
410
                                         coeffsPrecList[index])
411
        print "cvp_polynomial_coeffs - current coefficient rounded:", currentCoeff
412
        currentCoeff *= 2^(minCoeffsExpList[index])
413
        print "cvp_polynomial_coeffs - current coefficient scaled :", currentCoeff
414
        currentCoeff *= 2^(-coeffsPrecList[index])
415
        print "cvp_polynomial_coeffs - current coefficient prec corrected :", currentCoeff
416
        currentCoeff *= 2^(-extraFuncScalingExp)
417
        print "cvp_polynomial_coeffs - current coefficient extra func scaled :", currentCoeff
418
        polynomialCoeffsList.append(currentCoeff)
419
    return polynomialCoeffsList
420
# En polynomial_coeffs_from_vect.
421
#
422
def cvp_polynomial_from_coeffs_and_exps(coeffsList, 
423
                                        expsList, 
424
                                        polyField = None,
425
                                        theVar = None):
426
    """
427
    Build a polynomial in the classical monomials (possibly lacunary) basis 
428
    from a list of coefficients and a list of exponents. The polynomial is in
429
    the polynomial field given as argument.
430
    """
431
    if len(coeffsList) != len(expsList):
432
        return None
433
    ## If no variable is given, "x" is used.
434
    ## If no polyField is given, we fall back on a polynomial field on RR.
435
    if theVar is None:
436
        if polyField is None:
437
            theVar = x
438
            polyField = RR[theVar]
439
        else:
440
            theVar = var(polyField.variable_name())
441
    else: # theVar is set.
442
        if polyField is None:
443
            polyField = RR[theVar]
444
        else: # Both the polyFiled and theVar are set: create a new polyField
445
            # with theVar. The original polyField is not affected by the change.
446
            polyField = polyField.change_var(theVar)  
447
    ## Seed the polynomial.
448
    poly = polyField(0)
449
    ## Append the terms.
450
    for coeff, exp in zip(coeffsList, expsList):
451
        poly += polyField(coeff * theVar^exp)
452
    return poly
453
# End cvp_polynomial_from_coeffs_and_exps.
454
#
455
def cvp_remez_all_poly_error_func_maxi(funct, 
456
                                        maxDegree, 
457
                                        lowerBound, 
458
                                        upperBound,
459
                                        precsList, 
460
                                        realField = None,
461
                                        contFracMaxErr = None):
462
    pass
463
    """
464
    For a given function f, a degree and an interval, compute the 
465
    maxima of the (f-remez_d(f)) function and those of the (f-truncRemez_d(f)) 
466
    function over the interval.
467
    """
468
# End cvp_remez_all_poly_error_func_maxi.
469
#
470
def cvp_remez_all_poly_error_func_zeros(funct, 
471
                                        maxDegree, 
472
                                        lowerBound, 
473
                                        upperBound,
474
                                        precsList, 
475
                                        realField = None,
476
                                        contFracMaxErr = None):
477
    """
478
    For a given function f, a degree and an interval, compute the 
479
    zeros of the (f-remez_d(f)) function and those of the (f-truncRemez_d(f)) 
480
    function over the interval. If the (f-truncRemez_d(f)) function has very 
481
    few zeros, compute the zeros of the derivative instead.
482
    TODO: change the final behaviour! Now!
483
    """
484
    ## If no realField argument is given try to retrieve it from the 
485
    #  bounds. If impossible (e.g. rational bound), fall back on RR. 
486
    if realField is None:
487
        try:
488
            ### Force failure if parent does not have prec() member.
489
            lowerBound.parent().prec()
490
            ### If no exception is thrown, set realField.
491
            realField = lowerBound.parent()
492
        except:
493
            realField = RR
494
    #print "Real field:", realField
495
    funcSa         = func
496
    funcAsStringSa = func._assume_str().replace("_SAGE_VAR_","",100)
497
    print "Function as a string:", funcAsStringSa
498
    ## Create the Sollya version of the function and compute the
499
    #  Remez approximant
500
    funcSo  = pobyso_parse_string(funcAsStringSa)
501
    pStarSo = pobyso_remez_canonical_sa_so(funcAsStringSa, 
502
                                           maxDegree, 
503
                                           lowerBound,
504
                                           upperBound)
505
    ## Compute the zeroes of the error function.
506
    ### First create the error function with copies since they are needed later.
507
    errorFuncSo = sollya_lib_build_function_sub(sollya_lib_copy_obj(pStarSo), 
508
                                                sollya_lib_copy_obj(funcSo))
509
    intervalSo = pobyso_range_from_bounds_sa_so(lowerBound, upperBound)
510
    errorFuncZerosSo = pobyso_dirty_find_zeros_so_so(errorFuncSo, intervalSo)
511
    pobyso_clear_obj(errorFuncSo) # Clears funcSo and pStarSo as well.
512
    #print "Zeroes of the error function from Sollya:"
513
    #pobyso_autoprint(errorFuncZerosSo)
514
    errorFuncZerosSa = pobyso_float_list_so_sa(errorFuncZerosSo)
515
    pobyso_clear_obj(errorFuncZerosSo)
516
    #print "\nZeroes of the error function from Sage:"
517
    #print errorFuncZerosSa
518
    #
519
    ## Deal with the truncated polynomial now.
520
    ### Create the formats list. Notice the "*" before the list variable name.
521
    truncFormatListSo = pobyso_build_list_of_ints_sa_so(*precsList)
522
    #print "Precisions list as Sollya object:", 
523
    pobyso_autoprint(truncFormatListSo)
524
    pTruncSo = pobyso_round_coefficients_so_so(pStarSo, truncFormatListSo)
525
    #print "Truncated polynomial:", ; pobyso_autoprint(pTruncSo)
526
    ### Compute the error function. This time we consume both the function
527
    #   and the polynomial.
528
    errorFuncSo = sollya_lib_build_function_sub(pTruncSo, 
529
                                                funcSo)
530
    errorFuncZerosSo = pobyso_dirty_find_zeros_so_so(errorFuncSo, intervalSo)
531
    pobyso_clear_obj(pStarSo)
532
    #print "Zeroes of the error function for the truncated polynomial from Sollya:"
533
    pobyso_autoprint(errorFuncZerosSo)
534
    errorFuncTruncZerosSa = pobyso_float_list_so_sa(errorFuncZerosSo)
535
    pobyso_clear_obj(errorFuncZerosSo)
536
    ## It may happen that the error function has only one or two zeros.
537
    #  In this case, we are interested in the variations and we consider the
538
    #  derivative
539
    if maxDegree > 3:
540
        if len(errorFuncTruncZerosSa) <= (maxDegree / 2):
541
            errorFuncDiffSo = pobyso_diff_so_so(errorFuncSo)
542
            errorFuncZerosSo = pobyso_dirty_find_zeros_so_so(errorFuncDiffSo,
543
                                                             intervalSo)
544
            errorFuncTruncZerosSa = pobyso_float_list_so_sa(errorFuncZerosSo)
545
            pobyso_clear_obj(errorFuncZerosSo)
546
            pobyso_clear_obj(errorFuncDiffSo) # Clears funcSo and pTruncSo as well.
547
    pobyso_clear_obj(errorFuncSo) # Clears funcSo and pTruncSo as well.
548
    ## Sollya objects clean up.
549
    pobyso_clear_obj(intervalSo)
550
    errorFuncZerosSa += errorFuncTruncZerosSa
551
    errorFuncZerosSa.sort()
552
    ## If required, convert the numbers to rational numbers.
553
    if not contFracMaxErr is None:
554
        for index in xrange(0, len(errorFuncZerosSa)):
555
            errorFuncZerosSa[index] = \
556
                errorFuncZerosSa[index].nearby_rational(contFracMaxErr)
557
    return errorFuncZerosSa
558
    #
559
# End remez_all_poly_error_func_zeros
560
#
561
def cvp_remez_poly_error_func_zeros(funct, 
562
                                    maxDegree, 
563
                                    lowerBound, 
564
                                    upperBound,
565
                                    realField = None,
566
                                    contFracMaxErr = None):
567
    """
568
    For a given function f, a degree and an interval, compute the 
569
    zeros of the (f-remez_d(f)) function.
570
    """
571
    ## If no realField argument is given try to retrieve it from the 
572
    #  bounds. If impossible (e.g. rational bound), fall back on RR. 
573
    if realField is None:
574
        try:
575
            ### Force failure if parent does not have prec() member.
576
            lowerBound.parent().prec()
577
            ### If no exception is thrown, set realField.
578
            realField = lowerBound.parent()
579
        except:
580
            realField = RR
581
    #print "Real field:", realField
582
    funcSa         = func
583
    funcAsStringSa = func._assume_str().replace("_SAGE_VAR_","",100)
584
    #print "Function as a string:", funcAsStringSa
585
    ## Create the Sollya version of the function and compute the
586
    #  Remez approximant
587
    funcSo  = pobyso_parse_string(funcAsStringSa)
588
    pStarSo = pobyso_remez_canonical_sa_so(funcAsStringSa, 
589
                                           maxDegree, 
590
                                           lowerBound,
591
                                           upperBound)
592
    ## Compute the zeroes of the error function.
593
    ### Error function creation consumes both pStarSo and funcSo.
594
    errorFuncSo = sollya_lib_build_function_sub(pStarSo, funcSo)
595
    intervalSo = pobyso_range_from_bounds_sa_so(lowerBound, upperBound)
596
    errorFuncZerosSo = pobyso_dirty_find_zeros_so_so(errorFuncSo, intervalSo)
597
    pobyso_clear_obj(errorFuncSo) # Clears funcSo and pStarSo as well.
598
    #print "Zeroes of the error function from Sollya:"
599
    #pobyso_autoprint(errorFuncZerosSo)
600
    errorFuncZerosSa = pobyso_float_list_so_sa(errorFuncZerosSo)
601
    pobyso_clear_obj(errorFuncZerosSo)
602
    ## Sollya objects clean up.
603
    pobyso_clear_obj(intervalSo)
604
    ## Converting to rational numbers, if required.
605
    if not contFracMaxErr is None:
606
        for index in xrange(0, len(errorFuncZerosSa)):
607
            errorFuncZerosSa[index] = \
608
                errorFuncZerosSa[index].nearby_rational(contFracMaxErr)
609
    return errorFuncZerosSa
610
    #
611
# End remez_poly_error_func_zeros
612
#
613
def cvp_round_to_bits(num, numBits):
614
    """
615
    Round "num" to "numBits" bits.
616
    @param num    : the number to round;
617
    @param numBits: the number of bits to round to.
618
    """
619
    if num == 0:
620
        return num
621
    log2ofNum  = 0
622
    numRounded = 0
623
    ## Avoid conversion to floating-point if not necessary.
624
    try:
625
        log2OfNum = num.abs().log2()
626
    except:
627
        log2OfNum = RR(num).abs().log2()
628
    ## Works equally well for num >= 1 and num < 1.
629
    log2OfNum = ceil(log2OfNum)
630
    # print "cvp_round_to_bits - Log2OfNum:", log2OfNum
631
    divMult = log2OfNum - numBits
632
    #print "cvp_round_to_bits - DivMult:", divMult
633
    if divMult != 0:
634
        numRounded = round(num/2^divMult) * 2^divMult
635
    else:
636
        numRounded = num
637
    return numRounded
638
# End cvp_round_to_bits
639
#
640
def cvp_vector_in_basis(vect, basis):
641
    """
642
    Compute the coordinates of "vect" in "basis" by
643
    solving a linear system.
644
    @param vect : the vector we want to compute the coordinates of
645
                  in coordinates of the ambient space;
646
    @param basis: the basis we want to compute the coordinates in
647
                  as a matrix relative to the ambient space.
648
    """
649
    ## Create the variables for the linear equations.
650
    varDeclString = ""
651
    basisIterationsRange = xrange(0, basis.nrows())
652
    ### Building variables declaration string.
653
    for index in basisIterationsRange:
654
        varName = "a" + str(index)
655
        if varDeclString == "":
656
            varDeclString += varName
657
        else:
658
            varDeclString += "," + varName
659
    ### Variables declaration
660
    varsList = var(varDeclString)
661
    sage_eval("var('" + varDeclString + "')")
662
    ## Create the equations
663
    equationString = ""
664
    equationsList = []
665
    for vIndex in xrange(0, len(vect)):
666
        equationString = ""
667
        for bIndex in basisIterationsRange:
668
            if equationString != "":
669
                equationString += "+"
670
            equationString += str(varsList[bIndex]) + "*" + str(basis[bIndex,vIndex])
671
        equationString += " == " + str(vect[vIndex])
672
        equationsList.append(sage_eval(equationString))
673
    ## Solve the equations system. The solution dictionnary is needed
674
    #  to recover the values of the solutions.
675
    solutions = solve(equationsList,varsList, solution_dict=True)
676
    #print "Solutions:", s
677
    ## Recover solutions in rational components vector.
678
    vectInBasis = vector(QQ, basis.nrows())
679
    ### There can be several solution, in the general case.
680
    #   Here, there is only one. For each solution, each 
681
    #   variable has to be searched for.
682
    for sol in solutions:
683
        for bIndex in basisIterationsRange:
684
            vectInBasis[bIndex] = sol[varsList[bIndex]]
685
    return vectInBasis
686
# End cpv_vector_in_basis.
687
#
688
print "... functions for CVP loaded."