Statistiques
| Branche: | Révision :

cvp / src / functions_for_cvp.sage @ 62861417

Historique | Voir | Annoter | Télécharger (11,1 ko)

1
"""@package functions_for_cvp
2
Auxiliary functions used for CVP.
3
"""
4
print "Functions for CVP loading..."
5
#
6
def cvp_babai(redBasis, redBasisGso, vect):
7
    """
8
    Closest plane vector implementation as per Babaï.
9
    @param redBasis   : a lattice basis, preferably a reduced one; 
10
    @param redBasisGSO: the GSO of the previous basis;
11
    @param vector     : a vector, in coordinated in the ambient 
12
                        space of the lattice
13
    @return the closest vector to the input, in coordinates in the 
14
                        ambient space of the lattice.
15
    """
16
    ## A deep copy is not necessary here.
17
    curVect = copy(vect)
18
    print "cvp_babai - Vector:", vect
19
    ## From index of last row down to 0.
20
    for vIndex in xrange(len(redBasis.rows())-1, -1, -1):
21
        curRBGSO = redBasisGso.row(vIndex)
22
        curVect = curVect - (round((curVect * curRBGSO)  / (curRBGSO * curRBGSO)) * redBasis.row(vIndex)) 
23
    return vect - curVect
24
# End cvp_babai
25
#
26
def cvp_bkz_reduce(intBasis, blockSize):
27
    """
28
    Thin and simplistic wrapper the HKZ function of the FP_LLL module.
29
    """
30
    fplllIntBasis = FP_LLL(intBasis)
31
    fplllIntBasis.BKZ(blockSize)
32
    return fplllIntBasis._sage_()
33
# End cvp_hkz_reduce.
34
#
35
def cvp_common_scaling_exp(precision, 
36
                           precisionFraction = None):
37
    """
38
    Compute the common scaling factor (a power of 2).
39
    The exponent is a fraction of the precision;
40
    A extra factor is computed for the vector,
41
    exra factors are computed for the basis vectors, all in the corresponding
42
    functions.
43
    """
44
    ## Set a default value for the precisionFraction to 1/2.
45
    if precisionFraction is None:
46
        precisionFraction = 3/4
47
    """
48
    minBasisVectsNorm = oo
49
    currentNorm = 0
50
    for vect in floatBasis.rows():
51
        currentNorm = vect.norm()
52
        print "Current norm:", currentNorm
53
        if currentNorm < minBasisVectsNorm:
54
            minBasisVectsNorm = currentNorm
55
    currentNorm = funcVect.norm()
56
    print "Current norm:", currentNorm
57
    if currentNorm < minBasisVectsNorm:
58
        minBasisVectsNorm = currentNorm
59
    ## Check if a push is need because the smallest norm is below 0.    
60
    powerForMinNorm = floor(log(minBasisVectsNorm)/log2)
61
    print "Power for min norm :", powerForMinNorm
62
    print "Power for precision:", ceil(precision*precisionFraction)
63
    if powerForMinNorm < 0:
64
        return 2^(ceil(precision*precisionFraction) - powerFromMinNorm)
65
    else:
66
    """
67
    return ceil(precision * precisionFraction)
68
# End cvp_common_scaling_factor.
69
#
70
def cvp_extra_basis_scaling_exps(precsList, minExponentsList):
71
    extraScalingExpsList = []
72
    for minExp, prec in zip(minExponentsList, precsList):
73
        if minExp - prec < 0:
74
            extraScalingExpsList.append(minExp - prec)
75
        else:
76
            extraScalingExpsList.append(0)
77
    return extraScalingExpsList
78
# End cvp_extra_basis_scaling_exps.
79
#
80
def cvp_extra_function_scaling_exp(floatBasis,
81
                                   floatFuncVect,
82
                                   maxExponentsList):
83
    """
84
    Compute the extra scaling exponent for the function vector in ordre to 
85
    guarantee that the maximum exponent can be reached for each element of the
86
    basis.
87
    """
88
    ## Check arguments
89
    if floatBasis.nrows() == 0 or \
90
       floatBasis.ncols() == 0 or \
91
       len(floatFuncVect)      == 0:
92
        return 1
93
    if len(maxExponentsList) != floatBasis.nrows():
94
        return None
95
    ## Compute the log of the norm of the function vector.
96
    funcVectNormLog  = log(floatFuncVect.norm())
97
    ## Compute the extra scaling factor for each vector of the basis.
98
    #  for norms ratios an maxExponentsList. 
99
    extraScalingExp = 0
100
    for (row, maxExp) in zip(floatBasis.rows(),maxExponentsList):
101
        rowNormLog     = log(row.norm())
102
        normsRatioLog2 = floor((funcVectNormLog - rowNormLog) / log2) 
103
        #print "Current norms ratio log2:", normsRatioLog2
104
        scalingExpCandidate = normsRatioLog2 - maxExp 
105
        #print "Current scaling exponent candidate:", scalingExpCandidate
106
        if scalingExpCandidate < 0:
107
            if -scalingExpCandidate > extraScalingExp:
108
                extraScalingExp = -scalingExpCandidate
109
    return extraScalingExp
110
# End cvp_extra_function_scaling_exp.
111
#
112
def cvp_float_basis(monomialsList, pointsList, realField):
113
    """
114
    For a given monomials list and points list, compute the floating-point
115
    basis matrix.
116
    """
117
    numRows    = len(monomialsList)
118
    numCols    = len(pointsList)
119
    if numRows == 0 or numCols == 0:
120
        return matrix(realField, 0, 0)
121
    #
122
    floatBasis = matrix(realField, numRows, numCols)
123
    for rIndex in xrange(0, numRows):
124
        for cIndex in xrange(0, numCols):
125
            floatBasis[rIndex,cIndex] = \
126
                monomialsList[rIndex](realField(pointsList[cIndex]))
127
    return floatBasis
128
# End cvp_float_basis
129
#
130
def cvp_float_vector_for_approx(func, 
131
                                basisPointsList,
132
                                realField):
133
    """
134
    Compute a floating-point vector for the function and the points list.
135
    """
136
    #
137
    ## Some local variables.
138
    basisPointsNum = len(basisPointsList)
139
    #
140
    ##
141
    vVect = vector(realField, basisPointsNum)
142
    for vIndex in xrange(0,basisPointsNum):
143
        vVect[vIndex] = \
144
            func(basisPointsList[vIndex])
145
    return vVect
146
# End cvp_float_vector_for_approx.
147
#
148
def cvp_hkz_reduce(intBasis):
149
    """
150
    Thin and simplistic wrapper the HKZ function of the FP_LLL module.
151
    """
152
    fplllIntBasis = FP_LLL(intBasis)
153
    fplllIntBasis.HKZ()
154
    return fplllIntBasis._sage_()
155
# End cvp_hkz_reduce.
156
#
157
def cvp_int_basis(floatBasis, 
158
                  commonScalingExp, 
159
                  extraScalingExpsList):
160
    """
161
    From the float basis, the common scaling factor and the extra exponents 
162
    compute the integral basis.
163
    """
164
    ## Checking arguments.
165
    if floatBasis.nrows() != len(extraScalingExpsList):
166
        return None
167
    intBasis = matrix(ZZ, floatBasis.nrows(), floatBasis.ncols())
168
    for rIndex in xrange(0, floatBasis.nrows()):
169
        for cIndex in xrange(0, floatBasis.ncols()):
170
            intBasis[rIndex, cIndex] = \
171
            floatBasis[rIndex, cIndex] * \
172
            2^(commonScalingExp + extraScalingExpsList[rIndex])
173
    return intBasis
174
# End cvp_int_basis.
175
#
176
def cvp_int_vector_for_approx(floatVect, commonScalingExp, extraScalingExp):
177
    totalScalingFactor = 2^(commonScalingExp + extraScalingExp)
178
    intVect = vector(ZZ, len(floatVect))
179
    for index in xrange(0, len(floatVect)):
180
        intVect[index] = (floatVect[index] * totalScalingFactor).round()
181
    return intVect
182
# End cvp_int_vector_for_approx.
183
#
184
def cvp_lll_reduce(intBasis):
185
    """
186
    Thin and simplistic wrapper around the LLL function
187
    """
188
    return intBasis.LLL()
189
# End cvp_lll_reduce.
190
#
191
def cvp_monomials_list(exponentsList, varName = None):
192
    """
193
    Create a list of monomials corresponding to the given exponentsList.
194
    Monomials are defined as functions.
195
    """
196
    monomialsList = []
197
    for exponent in exponentsList:
198
        if varName is None:
199
            monomialsList.append((x^exponent).function(x))
200
        else:
201
            monomialsList.append((varName^exponent).function(varName))
202
    return monomialsList
203
# End cvp_monomials_list.
204
#
205
def cvp_polynomial_coeffs_from_vect(cvpVectInBasis,
206
                                   coeffsPrecList, 
207
                                   minCoeffsExpList,
208
                                   extraFuncScalingExp):
209
    numElements = len(cvpVectInBasis)
210
    ## Arguments check.
211
    if numElements != len(minCoeffsExpList) or \
212
       numElements != len(coeffsPrecList):
213
        return None
214
    polynomialCoeffsList = []
215
    for index in xrange(0, numElements):
216
        currentCoeff = cvp_round_to_bits(cvpVectInBasis[index],
217
                                         coeffsPrecList[index])
218
        print "cvp_polynomial_coeffs - current coefficient rounded:", currentCoeff
219
        currentCoeff *= 2^(minCoeffsExpList[index])
220
        print "cvp_polynomial_coeffs - current coefficient scaled :", currentCoeff
221
        currentCoeff *= 2^(-coeffsPrecList[index])
222
        print "cvp_polynomial_coeffs - current coefficient prec corrected :", currentCoeff
223
        currentCoeff *= 2^(-extraFuncScalingExp)
224
        print "cvp_polynomial_coeffs - current coefficient extra func scaled :", currentCoeff
225
        polynomialCoeffsList.append(currentCoeff)
226
    return polynomialCoeffsList
227
# En polynomial_coeffs_from_vect.
228
#
229
def cvp_round_to_bits(num, numBits):
230
    """
231
    Round "num" to "numBits" bits.
232
    @param num    : the number to round;
233
    @param numBits: the number of bits to round to.
234
    """
235
    if num == 0:
236
        return num
237
    log2ofNum  = 0
238
    numRounded = 0
239
    ## Avoid conversion to floating-point if not necessary.
240
    try:
241
        log2OfNum = num.abs().log2()
242
    except:
243
        log2OfNum = RR(num).abs().log2()
244
    ## Works equally well for num >= 1 and num < 1.
245
    log2OfNum = ceil(log2OfNum)
246
    # print "cvp_round_to_bits - Log2OfNum:", log2OfNum
247
    divMult = log2OfNum - numBits
248
    #print "cvp_round_to_bits - DivMult:", divMult
249
    if divMult != 0:
250
        numRounded = round(num/2^divMult) * 2^divMult
251
    else:
252
        numRounded = num
253
    return numRounded
254
# End cvp_round_to_bits
255
#
256
def cvp_vector_in_basis(vect, basis):
257
    """
258
    Compute the coordinates of "vect" in "basis" by
259
    solving a linear system.
260
    @param vect : the vector we want to compute the coordinates of
261
                  in coordinates of the ambient space;
262
    @param basis: the basis we want to compute the coordinates in
263
                  as a matrix relative to the ambient space.
264
    """
265
    ## Create the variables for the linear equations.
266
    varDeclString = ""
267
    basisIterationsRange = xrange(0, basis.nrows())
268
    ### Building variables declaration string.
269
    for index in basisIterationsRange:
270
        varName = "a" + str(index)
271
        if varDeclString == "":
272
            varDeclString += varName
273
        else:
274
            varDeclString += "," + varName
275
    ### Variables declaration
276
    varsList = var(varDeclString)
277
    sage_eval("var('" + varDeclString + "')")
278
    ## Create the equations
279
    equationString = ""
280
    equationsList = []
281
    for vIndex in xrange(0, len(vect)):
282
        equationString = ""
283
        for bIndex in basisIterationsRange:
284
            if equationString != "":
285
                equationString += "+"
286
            equationString += str(varsList[bIndex]) + "*" + str(basis[bIndex,vIndex])
287
        equationString += " == " + str(vect[vIndex])
288
        equationsList.append(sage_eval(equationString))
289
    ## Solve the equations system. The solution dictionnary is needed
290
    #  to recover the values of the solutions.
291
    solutions = solve(equationsList,varsList, solution_dict=True)
292
    #print "Solutions:", s
293
    ## Recover solutions in rational components vector.
294
    vectInBasis = vector(QQ, basis.nrows())
295
    ### There can be several solution, in the general case.
296
    #   Here, there is only one. For each solution, each 
297
    #   variable has to be searched for.
298
    for sol in solutions:
299
        for bIndex in basisIterationsRange:
300
            vectInBasis[bIndex] = sol[varsList[bIndex]]
301
    return vectInBasis
302
# End cpv_vector_in_basis.
303
#
304
print "... functions for CVP loaded."