from polybori.PyPolyBoRi import Polynomial, BooleSet, BooleConstant from polybori.partial import PartialFunction from polybori.specialsets import all_monomials_of_degree_d, power_set from polybori.ll import ll_encode, ll_red_nf_redsb def add_bits_old(bits): """Adds n bits >>> from polybori import * >>> r=Ring(10) >>> add_bits_old([r.variable(i) for i in xrange(3)]) [x(0) + x(1) + x(2), x(0)*x(1) + x(0)*x(2) + x(1)*x(2)] >>> add_bits_old([r.variable(i) for i in xrange(4)]) [x(0) + x(1) + x(2) + x(3), x(0)*x(1) + x(0)*x(2) + x(0)*x(3) + x(1)*x(2) + x(1)*x(3) + x(2)*x(3)] """ bits = list(bits) n = len(bits) deg_d_monomials = [Polynomial(all_monomials_of_degree_d(i, bits)) for i in xrange(n + 1)] full = power_set(bits) bits_expr = [] # [sum(bits)] step = 0 while n > 2 ** step: to_one = sum([deg_d_monomials[i] for i in xrange(n + 1) if i & 2 ** step]) to_one = Polynomial(to_one) fun = PartialFunction(ones=to_one, zeros=full.diff(to_one)) poly = fun.interpolate_smallest_lex() bits_expr.append(poly) step = step + 1 return bits_expr def add_bits(bits): """Adds n bit variables, by Lucas theorem >>> from polybori import * >>> r=Ring(10) >>> add_bits([r.variable(i) for i in xrange(3)]) [x(0) + x(1) + x(2), x(0)*x(1) + x(0)*x(2) + x(1)*x(2)] >>> add_bits([r.variable(i) for i in xrange(4)]) [x(0) + x(1) + x(2) + x(3), x(0)*x(1) + x(0)*x(2) + x(0)*x(3) + x(1)*x(2) + x(1)*x(3) + x(2)*x(3), x(0)*x(1)*x(2)*x(3)] >>> add_bits([r.variable(0)]) [x(0)] """ bits = list(bits) if len(bits) < 2: return bits n = len(bits) bits_expr = [] # [sum(bits)] step = 0 while n >= 2 ** step: bits_expr.append(Polynomial(all_monomials_of_degree_d(2 ** step, bits) )) step = step + 1 return bits_expr def add_bit_expressions(bit_expressions): """Adds n bits, which can be arbitrary expressions, the first n variables of the ring are reversed for usage in this function. >>> from polybori import * >>> r=Ring(20) >>> add_bit_expressions([r.variable(i) for i in xrange(10,13)]) [x(10) + x(11) + x(12), x(10)*x(11) + x(10)*x(12) + x(11)*x(12)] >>> add_bit_expressions([r.variable(i) for i in xrange(10,13)]) [x(10) + x(11) + x(12), x(10)*x(11) + x(10)*x(12) + x(11)*x(12)] >>> add_bit_expressions([r.variable(11), r.variable(11)]) [0, x(11)] >>> add_bit_expressions([r.variable(11),r.variable(12),r.variable(13)]) [x(11) + x(12) + x(13), x(11)*x(12) + x(11)*x(13) + x(12)*x(13)] """ bit_variables = [] if bit_expressions: ring = bit_expressions[0].ring() bit_variables = [ring.variable(i) for i in xrange(len(bit_expressions) )] for expr in bit_expressions: assert BooleSet(expr).navigation().value() >= len(bit_variables) mapping = ll_encode([b + expr for (b, expr) in zip(bit_variables, bit_expressions)]) return [ll_red_nf_redsb(p, mapping) for p in add_bits(bit_variables)] def add_words(words): """def adds n words, this words are supposed to consists of list of their bits. >>> from polybori import * >>> r=Ring(1000) >>> add_words([[r.variable(100+i*3+j) for i in xrange(2)] for j in xrange(3)]) [x(100) + x(101) + x(102), x(100)*x(101) + x(100)*x(102) + x(101)*x(102) + x(103) + x(104) + x(105), x(100)*x(101)*x(103) + x(100)*x(101)*x(104) + x(100)*x(101)*x(105) + x(100)*x(102)*x(103) + x(100)*x(102)*x(104) + x(100)*x(102)*x(105) + x(101)*x(102)*x(103) + x(101)*x(102)*x(104) + x(101)*x(102)*x(105) + x(103)*x(104) + x(103)*x(105) + x(104)*x(105), x(100)*x(101)*x(103)*x(104)*x(105) + x(100)*x(102)*x(103)*x(104)*x(105) + x(101)*x(102)*x(103)*x(104)*x(105)] >>> res=add_words([[r.variable(100+i*9+j) for i in xrange(4)] for j in xrange(9)]) >>> [len(p) for p in res] [9, 45, 495, 12870, 735462, 70285482, 1891358892, 6435] >>> [p.deg() for p in res] [1, 2, 4, 8, 12, 18, 25, 33] >>> [p.n_nodes() for p in res] [9, 25, 54, 100, 153, 211, 249, 100] """ max_word_length = max((len(w) for w in words)) res = [] while len(words) > 0: words = [w for w in words if len(w) > 0] bits = add_bit_expressions([w[0] for w in words]) words = [w[1:] for w in words] if len(bits) > 0: res.append(bits[0]) words.append(bits[1:]) return res def multiply_by_addition(word_a, word_b): """Multiply two words >>> from polybori import Ring >>> r=Ring(1000) >>> x = r.variable >>> n=7 >>> res=multiply_by_addition([x(200+2*i) for i in xrange(n)], [x(200+2*i+1) for i in xrange(n)]) >>> [p.n_nodes() for p in res] [2, 4, 7, 17, 38, 85, 222, 630, 1358, 1702, 1713, 1430, 875, 214, 0] """ word_a = list(word_a) word_b = list(word_b) summands = [] if word_a: zero = word_a[0].ring().zero() elif word_b: zero = word_b[0].ring().zero() else: zero = BooleConstant(0) for (i, a) in enumerate(word_a): summands.append(i * [zero] + [a * b for b in word_b]) return add_words(summands) def _test(): import doctest doctest.testmod() if __name__ == "__main__": _test()