Recently the substitute function was fixed to handle an edge case when the object polynomial was a singleton not containing the subject variable (see [#24], [#25]). As far as I can tell that fix is correct for the stated case.
Unfortunately the fix introduced a bug where if the polynomial did contain from_var as a term of its own, all other monomials if any were thrown away.
Example:
in: x(0)*x(7) + x(1) + x(5)
x(1)->x(5) + x(7)
out: x(5) + x(7) (!)
Informally the buggy substitution method worked like so:
let q = poly / from_var
if q == 1 return to_var
I don't know what definition of this kind of multivariate polynomial division is actually used by BoolePolynomial here, but at a first pass I'd assume A / B, where B is the single variable b, finds quotient Q and remainder R s.t. A = B*Q + R and R has a lower degree in terms of the variable b than A. (Which in GF(2) means degree 0 so there's no b in R.) Then Q == 1 tells us R = A-B, not that A=B!
The code as it was written before #25 had, not withstanding its singleton bug, this implementation for the Q==1 case: poly -= from_var; poly += to_poly;. That might be faster. But it seemed conceptually simpler to me to always calculate and add the remainder.
Ironically I added back an isSingleton test because if quotient is how many b we have in A, and A is a single boolean monomial, and quotient is not 0, then b*quotient is that monomial. So we don't have to go find R (which holds for any degree of Q, not just degree 0).
(This is an area which clearly needs more unit tests and I've contributed one here in the PR.)
Recently the
substitute
function was fixed to handle an edge case when the object polynomial was a singleton not containing the subject variable (see [#24], [#25]). As far as I can tell that fix is correct for the stated case.Unfortunately the fix introduced a bug where if the polynomial did contain
from_var
as a term of its own, all other monomials if any were thrown away.Example:
x(0)*x(7) + x(1) + x(5)
x(1)
->
x(5) + x(7)
x(5) + x(7)
(!)Informally the buggy substitution method worked like so:
let q = poly / from_var
if q == 1 return to_var
I don't know what definition of this kind of multivariate polynomial division is actually used by BoolePolynomial here, but at a first pass I'd assume
A / B
, whereB
is the single variableb
, finds quotientQ
and remainderR
s.t.A = B*Q + R
andR
has a lower degree in terms of the variableb
thanA
. (Which in GF(2) means degree 0 so there's nob
inR
.) ThenQ == 1
tells usR = A-B
, not thatA=B
!The code as it was written before #25 had, not withstanding its singleton bug, this implementation for the
Q==1
case:poly -= from_var; poly += to_poly;
. That might be faster. But it seemed conceptually simpler to me to always calculate and add the remainder.Ironically I added back an
isSingleton
test because ifquotient
is how manyb
we have inA
, andA
is a single boolean monomial, and quotient is not 0, thenb*quotient
is that monomial. So we don't have to go findR
(which holds for any degree ofQ
, not just degree 0).(This is an area which clearly needs more unit tests and I've contributed one here in the PR.)
This fix also seems to resolve #27!