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." |