malb / algebraic_attacks (http://informatik.uni-bremen.de/~malb/blog.php)
This repository mainly holds code snippets for experimentation with algebraic attacks (and some general crypto code). The quality of this code is not 'release ready' at all. Although the code should work in general there is a lot of scratch, wrong and pathetic code in this repository. Also, some of this code dates back to my Diplomarbeit (master's thesis) and should be considered broken and outdated. By default all code listed here is released under the GPLv2+. Don't hesitate to ping me if you need something under some more permissive license like BSD-style.
Clone this repository (size: 128.5 KB): HTTPS / SSH
$ hg clone http://bitbucket.org/malb/algebraic_attacks/
| commit 35: | ce280e2b1a19 |
| parent 34: | 3dd50c6be752 |
| branch: | default |
fixed a very stupid bug in PRESENT which made the polynomial system unecessarily hard
algebraic_attacks /
anf2cnf.py
| # Introduced |
|---|
1 |
d09b2120fe38 |
r""" |
2 |
d09b2120fe38 |
Boolean Polynomial SAT-Solver |
3 |
d09b2120fe38 |
|
4 |
abd22969c7b5 |
Given an ideal or polynomial system this module performs conversion to |
5 |
abd22969c7b5 |
the DIMACS CNF format, calls MiniSat2 on that input and parses the |
6 |
d09b2120fe38 |
output. |
7 |
d09b2120fe38 |
|
8 |
d09b2120fe38 |
AUHTOR: |
9 |
abd22969c7b5 |
|
10 |
abd22969c7b5 |
- Martin Albrecht - (2008-09) initial version |
11 |
d09b2120fe38 |
""" |
12 |
d09b2120fe38 |
|
13 |
d09b2120fe38 |
import commands |
14 |
d09b2120fe38 |
|
15 |
048a412a8b93 |
from sage.rings.polynomial.pbori import BooleanPolynomial, BooleanMonomial |
16 |
d09b2120fe38 |
from sage.misc.prandom import shuffle as do_shuffle |
17 |
d09b2120fe38 |
|
18 |
abd22969c7b5 |
from sage.all import * |
19 |
d09b2120fe38 |
|
20 |
d09b2120fe38 |
@cached_function |
21 |
abd22969c7b5 |
def cached_permutations(e): |
22 |
d09b2120fe38 |
""" |
23 |
abd22969c7b5 |
Cached version of ``Permutations`` |
24 |
d09b2120fe38 |
|
25 |
d09b2120fe38 |
Since this version is cached, the input must be hash-able, e.g. a |
26 |
d09b2120fe38 |
tuple. |
27 |
d09b2120fe38 |
|
28 |
d09b2120fe38 |
INPUT: |
29 |
d09b2120fe38 |
|
30 |
abd22969c7b5 |
- ``e`` - a tuple of things to permute. |
31 |
abd22969c7b5 |
|
32 |
abd22969c7b5 |
EXAMPLE:: |
33 |
abd22969c7b5 |
|
34 |
abd22969c7b5 |
sage: r1 = cached_permutations( (1,1,0,0) ) |
35 |
abd22969c7b5 |
sage: r2 = cached_permutations( (1,1,0,0) ) |
36 |
d09b2120fe38 |
sage: r1 is r2 |
37 |
d09b2120fe38 |
True |
38 |
d09b2120fe38 |
sage: r1 = Permutations( [1,1,0,0] ) |
39 |
d09b2120fe38 |
sage: r2 = Permutations( [1,1,0,0] ) |
40 |
d09b2120fe38 |
sage: r1 is r2 |
41 |
d09b2120fe38 |
False |
42 |
d09b2120fe38 |
""" |
43 |
d09b2120fe38 |
return list(Permutations(list(e))) |
44 |
d09b2120fe38 |
|
45 |
d09b2120fe38 |
class ANFSatSolver(SageObject): |
46 |
d09b2120fe38 |
""" |
47 |
abd22969c7b5 |
Solve a boolean polynomial system using MiniSat2. |
48 |
d09b2120fe38 |
""" |
49 |
048a412a8b93 |
def __init__(self, ring=None, c=None): |
50 |
abd22969c7b5 |
""" |
51 |
abd22969c7b5 |
Setup the SAT-Solver and reset internal data. |
52 |
d09b2120fe38 |
|
53 |
048a412a8b93 |
This function is also called from :meth:`__call__()` to pass |
54 |
048a412a8b93 |
in parameters. |
55 |
d09b2120fe38 |
|
56 |
d09b2120fe38 |
INPUT: |
57 |
d09b2120fe38 |
|
58 |
048a412a8b93 |
- ``ring`` - a boolean polynomial ring |
59 |
048a412a8b93 |
|
60 |
abd22969c7b5 |
- ``c`` - the cutting number ``>= 2`` (default: ``4``) |
61 |
abd22969c7b5 |
|
62 |
abd22969c7b5 |
EXAMPLE:: |
63 |
abd22969c7b5 |
|
64 |
048a412a8b93 |
sage: B = BooleanPolynomialRing(10,'x') |
65 |
048a412a8b93 |
sage: ANFSatSolver(B) |
66 |
048a412a8b93 |
ANFSatSolver(4) over Boolean PolynomialRing in x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 |
67 |
d09b2120fe38 |
|
68 |
d09b2120fe38 |
""" |
69 |
048a412a8b93 |
self._i = 1 # the maximal index for literals |
70 |
048a412a8b93 |
self.minus = -1 |
71 |
048a412a8b93 |
|
72 |
048a412a8b93 |
if hasattr(self,"_ring") and self._ring is not None: |
73 |
048a412a8b93 |
if ring is not None: |
74 |
048a412a8b93 |
assert(ring is self._ring) |
75 |
048a412a8b93 |
else: |
76 |
048a412a8b93 |
assert(ring is not None) |
77 |
048a412a8b93 |
self._ring = ring |
78 |
048a412a8b93 |
|
79 |
d09b2120fe38 |
if hasattr(self,"c") and c is None: |
80 |
d09b2120fe38 |
pass |
81 |
d09b2120fe38 |
elif c is None: |
82 |
d09b2120fe38 |
self.c = 4 |
83 |
d09b2120fe38 |
else: |
84 |
d09b2120fe38 |
if c<2: |
85 |
048a412a8b93 |
raise TypeError("c must be >= 2 but is %d."%(c,)) |
86 |
d09b2120fe38 |
self.c = c |
87 |
d09b2120fe38 |
|
88 |
d09b2120fe38 |
self.cnf_literal_map.clear_cache() |
89 |
048a412a8b93 |
self._gen_one() |
90 |
048a412a8b93 |
|
91 |
048a412a8b93 |
def _repr_(self): |
92 |
048a412a8b93 |
return "ANFSatSolver(%d) over %s"%(self.c,self._ring) |
93 |
d09b2120fe38 |
|
94 |
048a412a8b93 |
def __getattr__(self, name): |
95 |
048a412a8b93 |
if name == 'ring': |
96 |
048a412a8b93 |
return self._ring |
97 |
048a412a8b93 |
else: |
98 |
048a412a8b93 |
raise AttributeError("ANFSatSolver does not have an attribute names '%s'"%name) |
99 |
d09b2120fe38 |
|
100 |
d09b2120fe38 |
def _cnf_literal(self): |
101 |
d09b2120fe38 |
""" |
102 |
d09b2120fe38 |
Return a new variable for the CNF formulas. |
103 |
d09b2120fe38 |
|
104 |
abd22969c7b5 |
EXAMPLE:: |
105 |
abd22969c7b5 |
|
106 |
d09b2120fe38 |
sage: B.<x,y,z> = BooleanPolynomialRing() |
107 |
048a412a8b93 |
sage: anf2cnf = ANFSatSolver(B) |
108 |
d09b2120fe38 |
sage: anf2cnf._cnf_literal() |
109 |
d09b2120fe38 |
2 |
110 |
048a412a8b93 |
sage: anf2cnf._cnf_literal() |
111 |
048a412a8b93 |
3 |
112 |
d09b2120fe38 |
|
113 |
abd22969c7b5 |
.. note:: |
114 |
abd22969c7b5 |
|
115 |
abd22969c7b5 |
Increases the internal literal counter. |
116 |
d09b2120fe38 |
""" |
117 |
048a412a8b93 |
self._i += 1 |
118 |
048a412a8b93 |
return self._i-1 |
119 |
048a412a8b93 |
|
120 |
d09b2120fe38 |
@cached_method |
121 |
d09b2120fe38 |
def cnf_literal_map(self, m): |
122 |
abd22969c7b5 |
""" |
123 |
abd22969c7b5 |
Given a monomial ``m`` in a boolean polynomial ring return a |
124 |
abd22969c7b5 |
tuple ``((i,),(c0,c1,...))`` where ``i`` is the index of the |
125 |
abd22969c7b5 |
monomial ``m`` and ``c0,c1,...`` are clauses which encode the |
126 |
abd22969c7b5 |
relation between the monomial ``m`` and the variables |
127 |
abd22969c7b5 |
contained in ``m``. |
128 |
d09b2120fe38 |
|
129 |
abd22969c7b5 |
EXAMPLE:: |
130 |
d09b2120fe38 |
|
131 |
d09b2120fe38 |
sage: B.<x,y,z> = BooleanPolynomialRing() |
132 |
048a412a8b93 |
sage: anf2cnf = ANFSatSolver(B) |
133 |
d09b2120fe38 |
sage: anf2cnf.cnf_literal_map(B(1)) |
134 |
048a412a8b93 |
(1, ((1,),)) |
135 |
d09b2120fe38 |
|
136 |
d09b2120fe38 |
sage: anf2cnf.cnf_literal_map(x) |
137 |
abd22969c7b5 |
(2, ()) |
138 |
d09b2120fe38 |
|
139 |
d09b2120fe38 |
sage: anf2cnf.cnf_literal_map(x*y) |
140 |
abd22969c7b5 |
(4, [(2, -4), (3, -4), (4, -2, -3)]) |
141 |
d09b2120fe38 |
|
142 |
d09b2120fe38 |
sage: anf2cnf.cnf_literal_map(y) |
143 |
abd22969c7b5 |
(3, ()) |
144 |
d09b2120fe38 |
|
145 |
abd22969c7b5 |
.. note:: |
146 |
abd22969c7b5 |
|
147 |
abd22969c7b5 |
May call :meth:`_cnf_literal()` |
148 |
d09b2120fe38 |
""" |
149 |
d09b2120fe38 |
minus = self.minus |
150 |
d09b2120fe38 |
cnf_literal_map = self.cnf_literal_map |
151 |
d09b2120fe38 |
|
152 |
d09b2120fe38 |
if isinstance(m, BooleanPolynomial): |
153 |
d09b2120fe38 |
if len(m) == 1: |
154 |
d09b2120fe38 |
m = m.lm() |
155 |
d09b2120fe38 |
else: |
156 |
048a412a8b93 |
raise TypeError("Input must be monomial.") |
157 |
048a412a8b93 |
elif not isinstance(m, BooleanMonomial): |
158 |
048a412a8b93 |
raise TypeError("Input must be of type BooleanPolynomial.") |
159 |
d09b2120fe38 |
|
160 |
048a412a8b93 |
if m.deg() == 0: |
161 |
048a412a8b93 |
# adding the clause that 1 has to be True |
162 |
d09b2120fe38 |
monomial = self._cnf_literal() |
163 |
048a412a8b93 |
return monomial, ((monomial,),) |
164 |
048a412a8b93 |
|
165 |
abd22969c7b5 |
elif m.deg() == 1: |
166 |
d09b2120fe38 |
# a variable |
167 |
d09b2120fe38 |
monomial = self._cnf_literal() |
168 |
abd22969c7b5 |
return monomial, tuple() |
169 |
d09b2120fe38 |
|
170 |
d09b2120fe38 |
else: |
171 |
d09b2120fe38 |
# we need to encode the relationship between the monomial |
172 |
d09b2120fe38 |
# and its variables |
173 |
d09b2120fe38 |
variables = [cnf_literal_map(v) for v in m.variables()] |
174 |
d09b2120fe38 |
monomial = self._cnf_literal() |
175 |
d09b2120fe38 |
|
176 |
d09b2120fe38 |
# (a | -w) & (b | -w) & (w | -a | -b) <=> w == a*b |
177 |
d09b2120fe38 |
mon_map = [] |
178 |
d09b2120fe38 |
for v,_ in variables: |
179 |
abd22969c7b5 |
mon_map.append( (v, minus * monomial) ) |
180 |
abd22969c7b5 |
mon_map.append( (monomial,) + sum([(minus*v,) for v,_ in variables],tuple()) ) |
181 |
d09b2120fe38 |
|
182 |
abd22969c7b5 |
return monomial, mon_map |
183 |
d09b2120fe38 |
|
184 |
048a412a8b93 |
def _gen_one(self): |
185 |
d09b2120fe38 |
""" |
186 |
d09b2120fe38 |
Call this one before calling any other conversion function |
187 |
d09b2120fe38 |
""" |
188 |
048a412a8b93 |
self._one_element = self._ring(1).lm() |
189 |
048a412a8b93 |
cnf_one, mon_map = self.cnf_literal_map(self._one_element) |
190 |
d09b2120fe38 |
self._cnf_one = cnf_one |
191 |
d09b2120fe38 |
|
192 |
048a412a8b93 |
def cnf(self, F, shuffle=False, format='dimacs', **kwds): |
193 |
abd22969c7b5 |
""" |
194 |
abd22969c7b5 |
Return CNF for ``F``. |
195 |
d09b2120fe38 |
|
196 |
d09b2120fe38 |
INPUT: |
197 |
abd22969c7b5 |
|
198 |
abd22969c7b5 |
- ``shuffle`` - shuffle output list (default: ``False``) |
199 |
abd22969c7b5 |
|
200 |
abd22969c7b5 |
- ``format`` - either 'dimacs' for DIMACS or ``None`` for |
201 |
abd22969c7b5 |
tuple list (default: ``dimacs``) |
202 |
d09b2120fe38 |
|
203 |
d09b2120fe38 |
EXAMPLE: |
204 |
d09b2120fe38 |
sage: B.<a,b,c,d> = BooleanPolynomialRing() |
205 |
048a412a8b93 |
sage: solver = ANFSatSolver(B) |
206 |
abd22969c7b5 |
sage: print solver.cnf([a*b + c + 1, d + c, a + c]) |
207 |
abd22969c7b5 |
p cnf 6 16 |
208 |
abd22969c7b5 |
2 -4 0 |
209 |
abd22969c7b5 |
3 -4 0 |
210 |
abd22969c7b5 |
4 -2 -3 0 |
211 |
abd22969c7b5 |
1 0 |
212 |
abd22969c7b5 |
4 5 0 |
213 |
abd22969c7b5 |
-4 -5 0 |
214 |
abd22969c7b5 |
1 0 |
215 |
abd22969c7b5 |
5 6 1 0 |
216 |
abd22969c7b5 |
-5 -6 1 0 |
217 |
abd22969c7b5 |
-5 6 -1 0 |
218 |
abd22969c7b5 |
5 -6 -1 0 |
219 |
abd22969c7b5 |
1 0 |
220 |
abd22969c7b5 |
2 5 1 0 |
221 |
abd22969c7b5 |
-2 -5 1 0 |
222 |
abd22969c7b5 |
-2 5 -1 0 |
223 |
abd22969c7b5 |
2 -5 -1 0 |
224 |
d09b2120fe38 |
""" |
225 |
d09b2120fe38 |
self.__init__( **kwds) |
226 |
d09b2120fe38 |
|
227 |
abd22969c7b5 |
if get_verbose() >= 1: |
228 |
048a412a8b93 |
print "Parameters: c: %d, shuffle: %s"%(self.c,shuffle) |
229 |
d09b2120fe38 |
|
230 |
abd22969c7b5 |
C = [] |
231 |
d09b2120fe38 |
for f in F: |
232 |
abd22969c7b5 |
for c in self._process_polynomial(f): |
233 |
abd22969c7b5 |
C.append(c) |
234 |
d09b2120fe38 |
if shuffle: |
235 |
abd22969c7b5 |
do_shuffle(C) |
236 |
abd22969c7b5 |
|
237 |
abd22969c7b5 |
if get_verbose() >= 1: |
238 |
abd22969c7b5 |
a, b = len(C),len(uniq(C)) |
239 |
abd22969c7b5 |
ratio = float(a)/float(b) |
240 |
abd22969c7b5 |
print "|C|: %d, |uniq(C)|: %d, overhead: %1.3f"%(a,b,ratio - 1.0) |
241 |
abd22969c7b5 |
|
242 |
abd22969c7b5 |
if format == 'dimacs': |
243 |
abd22969c7b5 |
return self.to_dimacs(C) |
244 |
abd22969c7b5 |
else: |
245 |
abd22969c7b5 |
return C |
246 |
abd22969c7b5 |
|
247 |
abd22969c7b5 |
def to_dimacs(self, C): |
248 |
abd22969c7b5 |
index = max([max(map(abs,clause))for clause in C]) |
249 |
abd22969c7b5 |
nclauses = len(C) |
250 |
abd22969c7b5 |
|
251 |
abd22969c7b5 |
out = ["p cnf %d %d\n"%(index,nclauses)] |
252 |
abd22969c7b5 |
out.extend([" ".join(map(str,clause)) + " 0\n" for clause in C]) |
253 |
abd22969c7b5 |
return "".join(out) |
254 |
d09b2120fe38 |
|
255 |
d09b2120fe38 |
def _process_polynomial(self, f): |
256 |
d09b2120fe38 |
""" |
257 |
d09b2120fe38 |
EXAMPLE: |
258 |
d09b2120fe38 |
sage: B.<a,b,c,d> = BooleanPolynomialRing() |
259 |
048a412a8b93 |
sage: solver = ANFSatSolver(B) |
260 |
d09b2120fe38 |
sage: solver._process_polynomial(a*b + c + 1) |
261 |
d09b2120fe38 |
[(2, -4), (3, -4), (4, -2, -3), (1,), (4, 5), (-4, -5)] |
262 |
d09b2120fe38 |
""" |
263 |
d09b2120fe38 |
M, E = [], [] |
264 |
d09b2120fe38 |
cnf_literal_map = self.cnf_literal_map |
265 |
d09b2120fe38 |
for m in f: |
266 |
d09b2120fe38 |
mbar, mon_map = cnf_literal_map( m ) |
267 |
d09b2120fe38 |
E.extend( mon_map ) |
268 |
d09b2120fe38 |
M.append( mbar ) |
269 |
d09b2120fe38 |
|
270 |
d09b2120fe38 |
if len(M) > self.c: |
271 |
d09b2120fe38 |
for Mbar in self._split_xor_list(M): |
272 |
d09b2120fe38 |
E.extend(self._cnf_for_xor_list(Mbar)) |
273 |
d09b2120fe38 |
else: |
274 |
d09b2120fe38 |
E.extend( self._cnf_for_xor_list(M) ) |
275 |
d09b2120fe38 |
return E |
276 |
d09b2120fe38 |
|
277 |
abd22969c7b5 |
def _split_xor_list(self, monomial_list): |
278 |
d09b2120fe38 |
""" |
279 |
abd22969c7b5 |
Splits a list of monomials into sublists and introduces |
280 |
abd22969c7b5 |
connection variables. |
281 |
abd22969c7b5 |
|
282 |
abd22969c7b5 |
INPUT: |
283 |
abd22969c7b5 |
|
284 |
abd22969c7b5 |
- ``monomial_list`` - a list of indices already registered |
285 |
abd22969c7b5 |
with ``self``. |
286 |
abd22969c7b5 |
|
287 |
abd22969c7b5 |
EXAMPLE:: |
288 |
abd22969c7b5 |
|
289 |
048a412a8b93 |
sage: B = BooleanPolynomialRing(3,'x') |
290 |
048a412a8b93 |
sage: asolver = ANFSatSolver(B) |
291 |
abd22969c7b5 |
sage: l = [asolver._cnf_literal() for _ in range(5)]; l |
292 |
048a412a8b93 |
[2, 3, 4, 5, 6] |
293 |
abd22969c7b5 |
sage: asolver._split_xor_list(l) |
294 |
048a412a8b93 |
[[2, 3, 7], [7, 4, 5, 8], [8, 6]] |
295 |
d09b2120fe38 |
""" |
296 |
d09b2120fe38 |
c = self.c |
297 |
d09b2120fe38 |
|
298 |
abd22969c7b5 |
nm = len(monomial_list) |
299 |
abd22969c7b5 |
part_length = ceil((c-2)/ZZ(nm) * nm) |
300 |
abd22969c7b5 |
M = [] |
301 |
abd22969c7b5 |
|
302 |
abd22969c7b5 |
new_variables = [] |
303 |
abd22969c7b5 |
for j in range(0, nm, part_length): |
304 |
abd22969c7b5 |
m = new_variables + monomial_list[j:j+part_length] |
305 |
abd22969c7b5 |
if (j + part_length) < nm: |
306 |
abd22969c7b5 |
new_variables = [self._cnf_literal()] |
307 |
abd22969c7b5 |
m += new_variables |
308 |
abd22969c7b5 |
M.append(m) |
309 |
abd22969c7b5 |
return M |
310 |
d09b2120fe38 |
|
311 |
d09b2120fe38 |
def _cnf_for_xor_list(self, M): |
312 |
d09b2120fe38 |
minus = self.minus |
313 |
d09b2120fe38 |
|
314 |
d09b2120fe38 |
E = [] |
315 |
d09b2120fe38 |
|
316 |
d09b2120fe38 |
if self._cnf_one in M: |
317 |
d09b2120fe38 |
M.remove(self._cnf_one) |
318 |
d09b2120fe38 |
else: |
319 |
048a412a8b93 |
mbar, mon_map = self.cnf_literal_map(self._one_element) |
320 |
d09b2120fe38 |
M.append(mbar) |
321 |
d09b2120fe38 |
E.extend(mon_map) |
322 |
d09b2120fe38 |
|
323 |
d09b2120fe38 |
ll = len( M ) |
324 |
d09b2120fe38 |
ll2 = ll + 1 if ll%2 == 0 else ll |
325 |
d09b2120fe38 |
|
326 |
d09b2120fe38 |
for l in range(0, ll2, 2): |
327 |
d09b2120fe38 |
p = tuple([1]*l + [0]*(ll-l)) |
328 |
abd22969c7b5 |
for p in cached_permutations(p): |
329 |
abd22969c7b5 |
E.append( sum([(minus**p[i] * M[i],) for i in range(ll)],tuple()) ) |
330 |
d09b2120fe38 |
return E |
331 |
d09b2120fe38 |
|
332 |
d09b2120fe38 |
def __call__(self, F, **kwds): |
333 |
d09b2120fe38 |
""" |
334 |
d09b2120fe38 |
EXAMPLE: |
335 |
d09b2120fe38 |
sage: sr = mq.SR(1,1,1,4,gf2=True) |
336 |
d09b2120fe38 |
sage: F,s = sr.polynomial_system() |
337 |
d09b2120fe38 |
sage: B = BooleanPolynomialRing(F.ring().ngens(), F.ring().variable_names()) |
338 |
d09b2120fe38 |
sage: F = [B(f) for f in F if B(f)] |
339 |
048a412a8b93 |
sage: solver = ANFSatSolver(B) |
340 |
abd22969c7b5 |
sage: solution, t = solver(F) |
341 |
abd22969c7b5 |
sage: solution |
342 |
abd22969c7b5 |
{k001: 0, k002: 0, s003: 1, k000: 1, k003: 0, |
343 |
abd22969c7b5 |
x103: 0, w100: 0, w101: 0, w102: 1, s000: 1, |
344 |
abd22969c7b5 |
w103: 1, s002: 1, s001: 1, x102: 1, x101: 1, |
345 |
abd22969c7b5 |
x100: 1, k103: 0, k101: 0, k102: 0, k100: 1} |
346 |
d09b2120fe38 |
|
347 |
d09b2120fe38 |
sage: B.ideal(F).groebner_basis() |
348 |
abd22969c7b5 |
[k100 + k003 + 1, |
349 |
abd22969c7b5 |
k101 + k003, |
350 |
abd22969c7b5 |
k102, |
351 |
abd22969c7b5 |
k103 + k003, |
352 |
abd22969c7b5 |
x100 + 1, |
353 |
abd22969c7b5 |
... |
354 |
abd22969c7b5 |
k000 + k003 + 1, |
355 |
abd22969c7b5 |
k001, |
356 |
abd22969c7b5 |
k002 + k003] |
357 |
d09b2120fe38 |
""" |
358 |
abd22969c7b5 |
fn = tmp_filename() |
359 |
abd22969c7b5 |
have_poly = False |
360 |
d09b2120fe38 |
|
361 |
abd22969c7b5 |
if isinstance(F, str): |
362 |
abd22969c7b5 |
fh = open(fn,"w") |
363 |
abd22969c7b5 |
fh.write(self.cnf(F, format='dimacs', **kwds)) |
364 |
abd22969c7b5 |
fh.close() |
365 |
d09b2120fe38 |
|
366 |
abd22969c7b5 |
else: |
367 |
abd22969c7b5 |
p = iter(F).next() |
368 |
abd22969c7b5 |
if isinstance(p, BooleanPolynomial): |
369 |
abd22969c7b5 |
have_poly = True |
370 |
abd22969c7b5 |
self._ring = p.parent() |
371 |
abd22969c7b5 |
|
372 |
abd22969c7b5 |
fh = open(fn,"w") |
373 |
abd22969c7b5 |
fh.write(self.cnf(F, format='dimacs', **kwds)) |
374 |
abd22969c7b5 |
fh.close() |
375 |
abd22969c7b5 |
elif isinstance(p, tuple): |
376 |
abd22969c7b5 |
fh = open(fn,"w") |
377 |
abd22969c7b5 |
fh.write(self.to_dimacs(F)) |
378 |
abd22969c7b5 |
fh.close() |
379 |
abd22969c7b5 |
else: |
380 |
abd22969c7b5 |
raise TypeError("Type '%s' not supported."%(type(p),)) |
381 |
abd22969c7b5 |
|
382 |
abd22969c7b5 |
# call MiniSat |
383 |
d09b2120fe38 |
on = tmp_filename() |
384 |
d09b2120fe38 |
s = commands.getoutput("minisat2 %s %s"%(fn,on)) |
385 |
d09b2120fe38 |
|
386 |
abd22969c7b5 |
if get_verbose() >= 2: |
387 |
abd22969c7b5 |
|
388 |
abd22969c7b5 |
|
389 |
d09b2120fe38 |
print s |
390 |
d09b2120fe38 |
|
391 |
d09b2120fe38 |
s = s.splitlines() |
392 |
d09b2120fe38 |
for l in s: |
393 |
d09b2120fe38 |
if "CPU time" in l: |
394 |
d09b2120fe38 |
t = float(l[l.index(":")+1:l.rindex("s")]) |
395 |
d09b2120fe38 |
break |
396 |
d09b2120fe38 |
|
397 |
d09b2120fe38 |
res = open(on).read() |
398 |
d09b2120fe38 |
if res.startswith("UNSAT"): |
399 |
70d6b52f3812 |
return False, t |
400 |
d09b2120fe38 |
res = res[4:] |
401 |
d09b2120fe38 |
res = map(int, res.split(" ")) |
402 |
d09b2120fe38 |
|
403 |
abd22969c7b5 |
# parse result |
404 |
abd22969c7b5 |
if not have_poly: |
405 |
abd22969c7b5 |
return res, t |
406 |
abd22969c7b5 |
else: |
407 |
abd22969c7b5 |
return self.map_solution_to_variables(res), t |
408 |
abd22969c7b5 |
|
409 |
abd22969c7b5 |
def map_solution_to_variables(self, res, gd=None): |
410 |
abd22969c7b5 |
""" |
411 |
abd22969c7b5 |
""" |
412 |
abd22969c7b5 |
if gd is None: |
413 |
abd22969c7b5 |
gens = self._ring.gens() |
414 |
abd22969c7b5 |
gd = {} |
415 |
abd22969c7b5 |
cnf_literal_map = self.cnf_literal_map |
416 |
abd22969c7b5 |
for gen in gens: |
417 |
abd22969c7b5 |
try: |
418 |
abd22969c7b5 |
im, _ = cnf_literal_map(gen.lm()) |
419 |
abd22969c7b5 |
gd[im] = gen |
420 |
abd22969c7b5 |
except KeyError: |
421 |
abd22969c7b5 |
pass |
422 |
abd22969c7b5 |
|
423 |
d09b2120fe38 |
solution = {} |
424 |
d09b2120fe38 |
for r in res: |
425 |
d09b2120fe38 |
if abs(r) in gd: |
426 |
d09b2120fe38 |
if r>0: |
427 |
d09b2120fe38 |
solution[gd[abs(r)]] = 1 |
428 |
d09b2120fe38 |
else: |
429 |
d09b2120fe38 |
solution[gd[abs(r)]] = 0 |
430 |
abd22969c7b5 |
return solution |
431 |
d09b2120fe38 |
|
432 |
d09b2120fe38 |
def beta(F): |
433 |
d09b2120fe38 |
B = F.ring() |
434 |
d09b2120fe38 |
|
435 |
d09b2120fe38 |
n = F.nvariables() |
436 |
d09b2120fe38 |
m = F.ngens() |
437 |
d09b2120fe38 |
k = sum([len(f) for f in F]) |
438 |
d09b2120fe38 |
d = max([f.total_degree() for f in F]) |
439 |
d09b2120fe38 |
return k / float(m * sum([binomial(n,i) for i in range(0,d+1)])) |
440 |
d09b2120fe38 |
|
441 |
d09b2120fe38 |
