# HG changeset patch
# User Martin Albrecht <malb@informatik.uni-bremen.de>
# Date 1255373013 -3600
# Node ID e8436f9d468b13c91560af38f2839beeacfaa568
# Parent  f872a92f5f9afff4b4971afc82bf9270faec269b
implemented ring.var() and various functions required for PolyBoRi update

diff -r f872a92f5f9a -r e8436f9d468b c_lib/include/pb_wrap.h
--- a/c_lib/include/pb_wrap.h	Sat Oct 24 20:06:53 2009 -0700
+++ b/c_lib/include/pb_wrap.h	Mon Oct 12 19:43:33 2009 +0100
@@ -3,6 +3,7 @@
 #include "nf.h"
 #include "fglm.h"
 #include "interpolate.h"
+#include "randomset.h"
 #include "ccobject.h"
 
 // M4RI 
@@ -85,3 +86,4 @@
     strat.addNonTrivialImplicationsDelayed(strat.generators[i]);
 }
 
+#define PBPolyVector_set(v,i,p) v[i] = p
diff -r f872a92f5f9a -r e8436f9d468b module_list.py
--- a/module_list.py	Sat Oct 24 20:06:53 2009 -0700
+++ b/module_list.py	Mon Oct 12 19:43:33 2009 +0100
@@ -1245,7 +1245,8 @@
               libraries=['m4ri', 'polybori','pboriCudd','groebner','gd'],
               include_dirs = [SAGE_ROOT+'/local/include/cudd',
                               SAGE_ROOT+'/local/include/polybori',
-                              SAGE_ROOT+'/local/include/polybori/groebner'],
+                              SAGE_ROOT+'/local/include/polybori/groebner',
+                              "sage/libs/polybori"],
               depends = [SAGE_ROOT + "/local/include/polybori/polybori.h"],
               extra_compile_args = polybori_extra_compile_args,
               language = 'c++'),
diff -r f872a92f5f9a -r e8436f9d468b sage/crypto/mq/mpolynomialsystem.py
--- a/sage/crypto/mq/mpolynomialsystem.py	Sat Oct 24 20:06:53 2009 -0700
+++ b/sage/crypto/mq/mpolynomialsystem.py	Mon Oct 12 19:43:33 2009 +0100
@@ -1147,6 +1147,7 @@
                     ij = ij - len(r)
                 else:
                     return r[ij]
+            raise IndexError("index out of range")
 
     def __contains__(self, element):
         """
diff -r f872a92f5f9a -r e8436f9d468b sage/crypto/mq/mpolynomialsystemgenerator.py
--- a/sage/crypto/mq/mpolynomialsystemgenerator.py	Sat Oct 24 20:06:53 2009 -0700
+++ b/sage/crypto/mq/mpolynomialsystemgenerator.py	Mon Oct 12 19:43:33 2009 +0100
@@ -13,11 +13,21 @@
     """
 
     def __getattr__(self, attr):
+        """
+        EXAMPLE::
+
+            sage: from sage.crypto.mq.mpolynomialsystemgenerator import MPolynomialSystemGenerator
+            sage: msg = MPolynomialSystemGenerator()
+            sage: msg.R
+            Traceback (most recent call last):                                                      
+            ...
+            NotImplementedError    
+        """
         if attr == "R":
             self.R = self.ring()
             return self.R
         else:
-            raise AttributeError
+            raise AttributeError("'%s' object has no attribute '%s'"%(self.__class__,attr))
 
     def varformatstr(self, name):
         """
@@ -31,6 +41,15 @@
 
         INPUT:
             name -- string
+
+        EXAMPLE::
+
+            sage: from sage.crypto.mq.mpolynomialsystemgenerator import MPolynomialSystemGenerator
+            sage: msg = MPolynomialSystemGenerator()
+            sage: msg.varformatstr('K')
+            Traceback (most recent call last):                                                      
+            ...
+            NotImplementedError    
         """
         raise NotImplementedError
         
@@ -44,6 +63,15 @@
         INPUT:
             name -- string
             round -- integer index
+
+        EXAMPLE::
+
+            sage: from sage.crypto.mq.mpolynomialsystemgenerator import MPolynomialSystemGenerator
+            sage: msg = MPolynomialSystemGenerator()
+            sage: msg.varstrs('K', i)
+            Traceback (most recent call last):                                                      
+            ...
+            NotImplementedError    
         """
         raise NotImplementedError
 
@@ -55,12 +83,30 @@
         INPUT:
             name -- string
             round -- integer index
+
+        EXAMPLE::
+
+            sage: from sage.crypto.mq.mpolynomialsystemgenerator import MPolynomialSystemGenerator
+            sage: msg = MPolynomialSystemGenerator()
+            sage: msg.vars('K',0)
+            Traceback (most recent call last):                                                      
+            ...
+            NotImplementedError    
         """
         raise NotImplementedError
 
     def ring(self):
         """
         Return the ring in which the system is defined.
+
+        EXAMPLE::
+
+            sage: from sage.crypto.mq.mpolynomialsystemgenerator import MPolynomialSystemGenerator
+            sage: msg = MPolynomialSystemGenerator()
+            sage: msg.ring()
+            Traceback (most recent call last):                                                      
+            ...
+            NotImplementedError    
         """
         raise NotImplementedError
 
@@ -68,6 +114,15 @@
         """
         Return a block term ordering for the equation systems
         generated by self.
+
+        EXAMPLE::
+
+            sage: from sage.crypto.mq.mpolynomialsystemgenerator import MPolynomialSystemGenerator
+            sage: msg = MPolynomialSystemGenerator()
+            sage: msg.block_order()
+            Traceback (most recent call last):                                                      
+            ...
+            NotImplementedError    
         """
         raise NotImplementedError
 
@@ -78,12 +133,30 @@
         INPUT:
             P -- plaintext (vector, list)
             K -- key (vector, list)
+
+        EXAMPLE::
+
+            sage: from sage.crypto.mq.mpolynomialsystemgenerator import MPolynomialSystemGenerator
+            sage: msg = MPolynomialSystemGenerator()
+            sage: msg(None, None)
+            Traceback (most recent call last):                                                      
+            ...
+            NotImplementedError    
         """
         raise NotImplementedError
 
     def sbox(self):
         """
         Return SBox object for self.
+
+        EXAMPLE::
+
+            sage: from sage.crypto.mq.mpolynomialsystemgenerator import MPolynomialSystemGenerator
+            sage: msg = MPolynomialSystemGenerator()
+            sage: msg.sbox()
+            Traceback (most recent call last):                                                      
+            ...
+            AttributeError: '<class 'sage.crypto.mq.mpolynomialsystemgenerator.MPolynomialSystemGenerator'>' object has no attribute '_sbox'
         """
         return self._sbox
 
@@ -96,6 +169,15 @@
         INPUT:
             P -- plaintext (vector, list)
             K -- key (vector, list)
+
+        EXAMPLE::
+
+            sage: from sage.crypto.mq.mpolynomialsystemgenerator import MPolynomialSystemGenerator
+            sage: msg = MPolynomialSystemGenerator()
+            sage: msg.polynomial_system()
+            Traceback (most recent call last):                                                      
+            ...
+            NotImplementedError    
         """
         raise NotImplementedError
 
@@ -103,6 +185,15 @@
         """
         Return random element. Usually this is a list of elements in
         the base field of length 'blocksize'.
+
+        EXAMPLE::
+
+            sage: from sage.crypto.mq.mpolynomialsystemgenerator import MPolynomialSystemGenerator
+            sage: msg = MPolynomialSystemGenerator()
+            sage: msg.random_element()
+            Traceback (most recent call last):                                                      
+            ...
+            NotImplementedError    
         """
         raise NotImplementedError
 
diff -r f872a92f5f9a -r e8436f9d468b sage/libs/polybori/decl.pxd
--- a/sage/libs/polybori/decl.pxd	Sat Oct 24 20:06:53 2009 -0700
+++ b/sage/libs/polybori/decl.pxd	Mon Oct 12 19:43:33 2009 +0100
@@ -431,6 +431,8 @@
 
     PBPolyVector pb_gauss_on_polys "gauss_on_polys" (PBPolyVector inp)
 
+    PBPolyVector pb_easy_linear_factors "easy_linear_factors"(PBPoly p)
+
     PBPoly pb_substitute_variables "substitute_variables<std::vector<BoolePolynomial>, BoolePolynomial>" (PBPolyVector vec, PBPoly poly)
 
     void pb_append_block "BooleEnv::appendBlock" (int ind)
@@ -441,6 +443,11 @@
     char * pb_get_variable_name "BooleEnv::getVariableName" \
         (int idx)
 
+    PBSet pb_random_set "random_set" (PBMonom variables, int length)
+    void pb_set_random_seed "set_random_seed" (unsigned int seed)
+
     #M4RI initialization
     void m4ri_build_all_codes()
     void m4ri_destroy_all_codes()
+
+    void PBPolyVector_set(PBPolyVector v, int i, PBPoly p)
diff -r f872a92f5f9a -r e8436f9d468b sage/rings/polynomial/pbori.pyx
--- a/sage/rings/polynomial/pbori.pyx	Sat Oct 24 20:06:53 2009 -0700
+++ b/sage/rings/polynomial/pbori.pyx	Mon Oct 12 19:43:33 2009 +0100
@@ -1285,6 +1285,41 @@
 #
 ###
 
+    def var(self, i=0):
+        """
+        Returns the i-th generator of this boolean polynomial ring.
+        
+        INPUT:
+        
+        - ``i`` - an integer or a boolean monomial in one variable
+        
+        EXAMPLES::
+        
+            sage: P.<x,y,z> = BooleanPolynomialRing(3)
+            sage: P.var()
+            x
+            sage: P.var(2)
+            z
+            sage: m = x.monomials()[0]
+            sage: P.var(m)
+            x
+        
+        TESTS::
+        
+            sage: P.<x,y,z> = BooleanPolynomialRing(3, order='dp')
+            sage: P.var(0)
+            x
+        """
+        if PY_TYPE_CHECK(i, BooleanMonomial):
+            if len(i) == 1:
+                i = i.index()
+            else:
+                raise TypeError, "Boolean monomials must be in one variable only."
+        i = int(i)
+        if i < 0 or i >= self._pbring.nVariables():
+            raise ValueError, "Generator not defined."
+        return new_BP_from_DD(self, self._pbring.variable(self.pbind[i]))
+
     def _change_ordering(self, int order):
         r"""
         Change the ordering of this boolean polynomial ring. Do NOT call
@@ -4186,6 +4221,9 @@
           to ``True`` linear algebra takes affect in this
           block. (default: ``True``)
         
+        - "gauss_on_linear" - perform Gaussian elimination on linear
+           polynomials (default: ``True``)
+
         - ``selection_size`` - maximum number of polynomials for
           parallel reductions (default: ``1000``)
         
@@ -4257,9 +4295,9 @@
         if "redsb" not in kwds:
             kwds["redsb"]=True
         set_cring(self.ring())
-        #_sig_on
+        _sig_on
         gb = groebner_basis(self.gens(), **kwds)
-        #_sig_off
+        _sig_off
         if kwds.get("deg_bound", False) is False:
             g = GroebnerStrategy()
             for p in gb:
@@ -5238,6 +5276,36 @@
             raise IndexError
         return new_BP_from_PBPoly(self._parent, self._vec.get(i))
 
+
+    def __setitem__(self, ind, p):
+        """
+        EXAMPLE::
+
+            sage: B.<a,b,c,d,e,f> = BooleanPolynomialRing()
+            sage: from polybori import BooleanPolynomialVector
+            sage: l = [B.random_element() for _ in range(3)]
+            sage: v = BooleanPolynomialVector(l)
+            sage: len(v)
+            3
+            sage: v[0] = a; v[0]
+            a
+            sage: v[-1] = b; v[-1]
+            b
+            sage: v[3] = c
+            Traceback (most recent call last):                                                     
+            ...
+            IndexError
+        """
+        cdef long i = int(ind)
+        while i < 0:
+            i += self._vec.size()
+        if i >= self._vec.size():
+            raise IndexError
+        if not PY_TYPE_CHECK(p, BooleanPolynomialVector):
+            p = self._parent(p)
+
+        PBPolyVector_set(self._vec, i, (<BooleanPolynomial>p)._pbpoly)
+
     def append(self, el):
         """
         Append the element ``el`` to this vector.
@@ -5416,7 +5484,7 @@
             sage: red.add_generator(y*z + z)
 
             sage: red.head_normal_form(x + y*z)
-            x + y*z
+            y + z + 1
 
             sage; red.nf(x + y*z)
             y + z + 1
@@ -6983,6 +7051,53 @@
             _vec.append(f)
     return new_BP_from_PBPoly((<BooleanPolynomialRing>poly._parent), pb_substitute_variables(_vec._vec, poly._pbpoly))
 
+
+def set_random_seed(seed):
+    """
+    The the PolyBoRi random seed to ``seed``
+
+    EXAMPLE::
+
+        sage: from polybori import random_set, set_random_seed
+        sage: B.<a,b,c,d,e> = BooleanPolynomialRing()
+        sage: (a*b*c*d).lm()
+        a*b*c*d
+        sage: set_random_seed(1337)
+        sage: random_set((a*b*c*d).lm(),2)
+        {{b,c}, {b}}
+        sage: random_set((a*b*c*d).lm(),2)
+        {{a,c}, {}}
+
+        sage: set_random_seed(1337)
+        sage: random_set((a*b*c*d).lm(),2)
+        {{b,c}, {b}}
+        sage: random_set((a*b*c*d).lm(),2)
+        {{a,c}, {}}
+    """
+    pb_set_random_seed(seed)
+
+def random_set(BooleanMonomial variables, length):
+    """
+    Return a random set of monomials with ``length`` elements with
+    each element in the variables ``variables``.
+
+    EXAMPLE::
+
+        sage: from polybori import random_set, set_random_seed
+        sage: B.<a,b,c,d,e> = BooleanPolynomialRing()
+        sage: (a*b*c*d).lm()
+        a*b*c*d
+        sage: set_random_seed(1337)
+        sage: random_set((a*b*c*d).lm(),10)
+        {{a,b,c,d}, {a,b,d}, {a,c}, {a,d}, {a}, {b,c}, {b}, {c,d}, {c}, {}}
+    """
+    cdef PBSet r
+    r =  pb_random_set(variables._pbmonom, length)
+    return new_BS_from_PBSet(r, variables._ring)
+
+def easy_linear_factors(BooleanPolynomial p):
+    return new_BPV_from_PBPolyVector(p._parent, pb_easy_linear_factors(p._pbpoly))
+
 def unpickle_BooleanPolynomial(ring, string): 
     """ 
     Unpickle boolean polynomials
