(1) You can create a BooleanFunction of 0 variables (a constant), but you cannot save it to a file. Same with a BooleanFunction of 1 variable.
(2) You cannot evaluate the algebraic normal form of a BooleanFunction of 0 variables. In addition, the error message incorrectly says that the number of variables must be greater than 1, but you *can* evaluate the algebraic normal form of a function of 1 variable.
Hi Nils,
I have now done a small amount of investigation, and my results and replies are below.
All the best, Paul
On Thursday, 14 July 2016 8:15:35 AM AEST you wrote:
> On Thursday, July 14, 2016 at 6:18:16 AM UTC-7, Paul Leopardi wrote:
> > (1) You can create a BooleanFunction of 0 variables (a constant), but you
> > cannot save it to a file. Same with a BooleanFunction of 1 variable.
> >
> > This seems to be connected with the truth-table problems: The "pickling"
>
> essentially stores
>
> <BooleanFunction>.truth_table(format="hex")
>
> which uniquely determines the function for n>=2 variables (since then the
> number of bits in the truth table is a multiple of 4 and hence lines up
> with the length of hex numbers), but fails to uniquely determine the number
> of variables uniquely if n<2. The pickle format would need adjustment to
> reliably handle the n=0,1 cases.
>
> We could get the right result by changing
>
> sage.crypto.boolean_function.BooleanFunction
>
> to
>
> def __reduce__(self):
> if self.nvariables() <2:
> return unpickle_BooleanFunction, (self.truth_table(format='int'),)
> else
> unpickle_BooleanFunction, (self.truth_table(format='hex'),)
If that could be done cleanly without breaking existing code, I can't see why not.
> > (2) You cannot evaluate the algebraic normal form of a BooleanFunction of
> > 0 variables. In addition, the error message incorrectly says that the
> > number of variables must be greater than 1, but you *can* evaluate the
> > algebraic normal form of a function of 1 variable.
> >
> > As your traceback shows, this error originates in the
>
> BooleanPolynomialRing parent (which is also returned). It is documented as
> needing n>1, but as you point out it does seem to handle n=1 more or less
> correctly as well (perhaps other functionality breaks).
The case n=1 seems OK using Sage 7.2 Ubuntu PPA:
sage: b0 = BooleanFunction([0,0])
sage: b0.algebraic_normal_form()
0
sage: b1 = BooleanFunction([1,0])
sage: b1.algebraic_normal_form()
x + 1
sage: b2 = BooleanFunction([0,1])
sage: b2.algebraic_normal_form()
x
sage: b3 = BooleanFunction([1,1])
sage: b3.algebraic_normal_form()
1
> This functionality is provided by PolyBoRi, which started as an
> independently maintained library but currently does not have an independent
> maintainer. I don't know what the process is to change/fix things there.
> Certainly it would seem a lot of work for not much benefit to add support
> for GF(2) in PolyBoRi itself.
>
> Would it be OK to represent 0-variable normal forms just as elements of
> GF(2)? In that case we could just add at the start of algebraic_normal_form
> the lines:
>
> if self._nvariables==0:
> return GF(2)(self._truth_table[0])
>
> and leave PolyBoRi alone. This would deserve special mention in the
> documentation because it would be an anomalous return type.
With n=1 and n=2, it is possible to create constant polynomials, but the constant 1 for n-1 does not equal the constant 1 for n=2:
sage: b3 = BooleanFunction([1,1])
sage: an3 = b3.algebraic_normal_form()
sage: an3
1
sage: an3.constant()
True
sage: an3.deg()
0
sage: bf = BooleanFunction([1,1,1,1])
sage: anf = bf.algebraic_normal_form()
sage: anf
1
sage: anf.constant()
True
sage: anf.deg()
0
sage: anf == an3
False
As for what you decide to do for n=0, it is up to you. I will work around it for now.
--
Paul Leopardi - https://sites.google.com/site/paulleopardi/