How to recover an image from another given image - image

If I have a grey-scale, square image (1) and I rotate a copy of it by 90 degrees. I create a new image (2) where the pixels are the sum of the original and rotated images. My question is if I only have image 2 how can I recover the original image 1?

The short answer is: you can't recover the original image.
Proof:
Assume 2x2 image:
I = [a b]
[c d]
J = I + rot90(I) = [ a + b, b + d] = [E F
[ a + c, c + d] G H]
Now lets try to solve the linear equation system:
E = a + b + 0 + 0
F = 0 + b + 0 + d
G = a + 0 + c + 0
H = 0 + 0 + c + d
A = [a, b, 0, 0 u = [a v = [E
0, b, 0, d b F
a, 0, c, 0 c G
0, 0, c, d] d] H]
v = A*u
In order to extract u, matrix A must be invertibale.
but det(A) = 0, so there are infinite possible solutions.
I tried an iterative approach.
I implemented it in MATLAB.
I played with it a little, and found out that applying bilateral filter, and moderated sharpening, improves the reconstructed result.
There are probably better heuristics, that I can't think off.
Here is the MATLAB implementation:
I = im2double(imread('cameraman.tif'))/2; %Read input sample image and convert to double
J = I + rot90(I); %Sum of I and rotated I.
%Initial guess.
I = ones(size(J))*0.5;
h_fig = figure;
ax = axes(h_fig);
h = imshow(I/2);
alpha = 0.1;
beta = 0.01;
%100000 iterations.
for i = 1:100000
K = I + rot90(I);
E = J - K; %E is the error matrix.
I = I + alpha*E;
if mod(i, 100) == 0
if (i < 100000*0.9)
I = imsharpen(imbilatfilt(I), 'Amount', 0.1);
end
h.CData = I*2;
ax.Title.String = num2str(i);
pause(0.01);
beta = beta * 0.99;
end
end
Sum of I and rot90(I):
Original image:
Reconstructed image:

Related

Binary splitting algorithm needed for nested hypergeometric-type rational sums

There are some good sources on-line to implement fast summation using binary splitting techniques. For example, Ch. 20, Jörg Arndt Book, (2004), Cheng et al. (2007) and papers from Haible and Papanikolaou (1997) and distributed with the CLN library source code. From this last article, the following notes apply to the evaluation of this kind of linearly convergent series (Type 1)
S = SUM(n=0,+oo,a(n)/b(n)*PROD(k=0,n,p(k)/q(k)))
where a(n), b(n), p(n), q(n) are integers with O(log N) bits. The most often used
case is that a(n), b(n), p(n), q(n) are polynomials in n with integer coefficients. Sum S is computed considering the following sequence of partial series with given two index bounds [n1, n2]
S(n1,n2) = SUM(n=n1,n2-1,a(n)/b(n)*PROD(k=n1,n,p(k)/q(k))
S(n1,n2) are not computed directly. Instead, the product of integers
P = p(n1) ... p(n2-1)
Q = q(n1) ... q(n2−1)
B = b(n1) ... b(n2-1)
T = B Q S
are computed recursively by binary splitting until n2 - n1 < 5 when these are computed directly. Choose an index nm in the middle of n1 and n2, compute the components Pl, Ql, Bl , Tl belonging to the interval n1 =< n < nm, compute the components Pr, Qr , Br, Tr belonging to the interval nm =< n < n2 and set these products and sums
P = Pl Pr
Q = Ql Qr,
B = Bl Br
T = Br Qr Tl + Bl Pl Tr
Finally, this algorithm is applied to n1 = 0 and n2 = nmax = O(N), and a final floating-point division
S = T/(B Q)
is performed.
The bit complexity of computing S with N bits of precision is O((log N)^2 M(N)) where M(N) is the bit complexity of the multiplication of two N-bit numbers.
A slightly modified but more complex series (Type 2) that is found in the last reference above can be also summed by binary splitting. It has an additional inner sum of rationals where c(n) and d(n) are integers with O(log N) bits
U = SUM(n=0,+oo,a(n)/b(n) * PROD(k=0,n,p(k)/q(k)) * SUM(m=0,n,c(m)/d(m)))
We consider these partial sums
U(n1,n2) = SUM(n=n1,n2-1,a(n)/b(n) * PROD(k=n1,n,p(k)/q(k)) * SUM(m=n1,n,c(m)/d(m)))
The algorithm is a variation of the above as follows.
P = p(n1) ... p(n2-1)
Q = q(n1) ... q(n2−1)
B = b(n1) ... b(n2-1)
T = B Q S
D = d(n1) ... d(n2-1)
C = D (c(n1)/d(n1) + ... + c(n2-1)/d(n2-1))
V = D B Q U
If n2 - n1 =< 4 these values are computed directly. If n2 - n1 > 4 they are computed by binary splitting. Choose an index nm in the middle of n1 and n2, compute the components Pl, Ql, Bl , Tl, Dl, Cl, Vl belonging to the interval n1 =< n < nm, compute the components Pr, Qr , Br, Tr, Dr, Cr, Vr belonging to the interval nm =< n < n2 and set these products and sums
P = Pl Pr
Q = Ql Qr
B = Bl Br
T = Br Qr Tl + Bl Pl Tr
D = Dl Dr
C = Cl Dr + Cr Dl
V = Dr Br Qr Vl + Dr Cl Bl Pl Tr + Dl Bl Pl Vr
At last, this algorithm is applied to n1 = 0 and n2 = nmax = O(N), and final floating point divisions are performed
S = T / (B Q)
V = U / (D B Q)
I have programmed both algorithms in Pari-GP and applied them to compute some mathematical constants using Chudnovsky's formula for Pi, this formula for Catalan Constant and more. (I have got more than 1000000 decimal digits in some cases under this platform). This code has been used to compute some difficult series as well.
I want to go one step ahead to accelerate some series by mixing binary splitting algorithm and levin-type sequence transformations. To do this I need to find the binary splitting relationships for a slight extension of these series.
W = SUM(n=0,+oo,a(n)/b(n) * PROD(k=0,n,p(k)/q(k)) * SUM(m=0,n,c(m)/d(m) * PROD(i=0,m,f(i)/g(i))))
It has has an additional product of rationals inside the inner sum where f(n) and g(n) are integers with O(log N) bits. These series are not hypergeometric but they are nested hypergeometric type sums. I think this algorithm might be derived from these partial series
W(n1,n2) = SUM(n=n1,n2-1,a(n)/b(n) * PROD(k=n1,n,p(k)/q(k)) * SUM(m=n1,n,c(m)/d(m) * PROD(i=n1,m,f(i)/g(i))))
I would very much appreciate if someone can derive the product and sum steps to bin-split this type of series.
I will leave the PARI-GP code for computing fast linearly convergent series of type 1 and 2 as explained. Use ?sumbinsplit for help. There are some Testing examples for Type 2 series as well. You can un-comment one of them and use
precision(-log10(abs(sumbinsplit(~F)[1]/s-1)),ceil(log10(Digits())));
to check it.
\\ ANSI COLOR CODES
{
DGreen = Dg = "\e[0;32m";
Brown = Br = "\e[0;33m";
DCyan = Dc = "\e[0;36m";
Purple = Pr = "\e[0;35m";
Gray = Gy = "\e[0;37m";
Red = Rd = "\e[0;91m";
Green = Gr = "\e[0;92m";
Yellow = Yw = "\e[0;93m";
Blue = Bl = "\e[0;94m";
Magenta = Mg = "\e[0;95m";
Cyan = Cy = "\e[0;96m";
Reset = "\e[0m";
White = Wh = "\e[0;97m";
Black = Bk = "\e[0;30m";
}
eps()={ my(e=1.); while(e+1. != 1., e>>=1); e; }
addhelp(eps,Str(Yw,"\n SMALLEST REAL NUMBER\n",Wh,"\n eps() ",Gr,"returns the minimum positive real number for current precision"));
log10(x) = if(x==0,log(eps()),log(x))/log(10);
Digits(n) = if(type(n) == "t_INT" && n > 0,default(realprecision,n); precision(1.), precision(1.));
addhelp(Digits,Str(Yw,"\n DIGITS\n",Wh,"\n Digits(n)",Gr," Sets global precision to",Wh," n",Gr," decimal digits.",Wh," Digits()",Gr," returns current global precision."));
addhelp(BinSplit2,Str(Yw,"\n SERIES BINARY SPLITTING (TYPE 2)\n\n",Wh,"BinSplit(~F,n1,n2)",Gr," for ",Wh,"F = [a(n),b(n),p(n),q(n),c(n),d(n)]",Gr," a vector of ",Br,"t_CLOSUREs",Gr," whose\n components are typically polynomials, computes by binary splitting method sums of type\n\n",Wh,"S2 = sum(n=n1,n2-1,a(n)/b(n)*prod(k=n1,n,p(k)/q(k))*sum(m=n1,n,c(m)/d(m)))\n\n",Gr,"Output: ",Wh," [P,Q,B,T,D,C,V]",Gr," integer valued algorithm computing parameters"));
addhelp(BinSplit1,Str(Yw,"\n SERIES BINARY SPLITTING (TYPE 1)\n\n",Wh,"BinSplit(~F,n1,n2)",Gr," for ",Wh,"F = [a(n),b(n),p(n),q(n)]",Gr," a vector of ",Br,"t_CLOSUREs",Gr," whose components\n are typically polynomials, computes by binary splitting method sums of type\n\n",Wh,"S1 = sum(n=n1,n2-1,a(n)/b(n)*prod(k=n1,n,p(k)/q(k)))\n\n",Gr,"Output: ",Wh,"[P,Q,B,T]",Gr," integer valued algorithm computing parameters"));
BinSplit2(~F, n1, n2) =
{
my( P = 1, Q = 1, B = 1, T = 0, D = 1, C = 0, V = 0,
LP, LQ, LB, LT, LD, LC, LV, RP, RQ, RB, RT, RD, RC, RV,
nm, tmp1 = 1, tmp2, tmp3 );
\\
\\ F = [a(n),b(n),p(n),q(n),c(n),d(n)]
\\
if( n2 - n1 < 5,
\\
\\ then
\\
for ( j = n1, n2-1,
LP = F[3](j);
LQ = F[4](j);
LB = F[2](j);
LD = F[6](j);
LC = F[5](j);
\\
tmp2 = LB * LQ;
tmp3 = LP * F[1](j) * tmp1;
T = T * tmp2 + tmp3;
C = C * LD + D * LC;
V = V * tmp2 * LD + C * tmp3;
P *= LP;
Q *= LQ;
B *= LB;
D *= LD;
tmp1 *= LP * LB;
),
\\
\\ else
\\
nm = (n1 + n2) >> 1;
\\
[RP,RQ,RB,RT,RD,RC,RV] = BinSplit2(~F, nm, n2);
[LP,LQ,LB,LT,LD,LC,LV] = BinSplit2(~F, n1, nm);
\\
tmp1 = RB * RQ;
tmp2 = LB * LP;
tmp3 = LC * RD;
\\
P = LP * RP;
Q = RQ * LQ;
B = LB * RB;
T = LT * tmp1 + RT * tmp2;
D = LD * RD;
C = RC * LD + tmp3;
V = RD * LV * tmp1 + ( RT * tmp3 + LD * RV ) * tmp2;
\\
\\ end if
);
return([P,Q,B,T,D,C,V]);
}
BinSplit1(~F, n1, n2) =
{
my( P = 1, Q = 1, B = 1, T = 0,
LP, LQ, LB, LT, RP, RQ, RB, RT,
tmp1 = 1, nm );
\\
\\ F = [a(n),b(n),p(n),q(n)]
\\
if( n2 - n1 < 5,
\\
\\ then
\\
for ( j = n1, n2-1,
LP = F[3](j);
LQ = F[4](j);
LB = F[2](j);
\\
T = T * LB * LQ + LP * F[1](j) * tmp1;
P *= LP;
Q *= LQ;
B *= LB;
\\
tmp1 *= LP * LB;
),
\\
\\ else
\\
nm = (n1 + n2) >> 1;
\\
[RP,RQ,RB,RT] = BinSplit1(~F, nm, n2);
[LP,LQ,LB,LT] = BinSplit1(~F, n1, nm);
\\
P = LP * RP;
Q = RQ * LQ;
B = LB * RB;
T = LT * RB * RQ + RT * LB * LP;
\\
\\ end if
);
return([P,Q,B,T]);
}
sumbinsplit(~F, n1 = 1, dgs = getlocalprec()) =
{
my( n = #F, P, Q, B, T, D, C, V, [a,b] = F[3..4] );
my( n2 = 1 + ceil(dgs*log(10)/log(abs(pollead(Pol(b(x),x))/pollead(Pol(a(x),x))))) );
\\
if ( n > 4, [P, Q, B, T, D, C, V] = BinSplit2(~F,n1,n2); return(1.*([V/D,T]/B/Q)),\
[P, Q, B, T] = BinSplit1(~F,n1,n2); return(1.*(T/B/Q)));
}
addhelp(sumbinsplit,Str(Yw,"\n LINEARLY CONVERGENT SERIES BINARY SPLITTING SUMMATION\n\n",Wh,"sumbinsplit( ~F, {n1 = 1}, {dgs = getlocalprec()} )\n\n",Gr,"for either ",Wh,"F = [a(n),b(n),p(n),q(n)] ",Gr,"or",Wh," F = [a(n),b(n),p(n),q(n),c(n),d(n)]",Gr," vectors of ",Br,"t_CLOSUREs",Gr," whose\n components are typically polynomials. It computes sums of type 1 or type 2 by binary splitting method\n\n (See BinSplit1, BinSplit2 help)\n\n",Wh,"n1",Gr," starting index (default 1),",Wh," dgs",Gr," result's floating precision\n\n",Yw,"OUTPUT:",Gr," either",Wh," S1",Gr," series value (Type 1) or ",Wh," [S2, S1]",Gr," series values [Type 2, Type1]"));
/* TESTINGS */
/*
Digits(100000);
a = n->1;
b = n->n;
p = n->n*(n<<1-1);
q = n->3*(3*n-1)*(3*n-2);
c = n->1;
d = n->n*(n<<1-1)<<1;
s = log(2)*(3*log(2)+Pi/2)/10-Pi^2/60;
F = [a,b,p,q,c,d];
*/
/*
Digits(100000);
s = -Pi*Catalan/2+33/32*zeta(3)+log(2)*Pi^2/24;
F = [n->1,n->n^2,n->n*(n<<1-1),n->3*(3*n-1)*(3*n-2),n->1,n->n*(n<<1-1)<<1];
\\ precision(-log10(abs(sumbinsplit(~F)[1]/s-1)),ceil(log10(Digits())));
*/
/*
Digits(10000);
a = n->1;
b = n->n<<1+1;
p = n->n<<1-1;
q = n->n<<3;
c = n->1;
d = n->(n<<1-1)^2;
s = Pi^3/648;
F = [a,b,p,q,c,d];
*/
/*
Digits(10000);
a = n->-1;
b = n->n^3;
p = n->-n;
q = n->(n<<1-1)<<1;
c = n->20*n-9;
d = n->n*(n<<1-1)<<1;
s = 2*Pi^4/75;
F = [a,b,p,q,c,d];
*/
/*
Digits(10000);
a = n->2;
b = n->n^2;
p = n->n;
q = n->(n<<1-1);
c = n->1;
d = n->n<<1-1;
s = 7*zeta(3)-2*Pi*Catalan;
F = [a,b,p,q,c,d];
*/
/*
Digits(10000);
a = n->1;
b = n->n^4;
p = n->n;
q = n->(n<<1-1)<<1;
c = n->36*n-17;
d = n->n*(n<<1-1)<<1;
s = 14*zeta(5)/9+5/18*Pi^2*zeta(3);
F = [a,b,p,q,c,d];
*/
/*
Digits(10000);
a = n->1;
b = n->n^2;
p = n->n;
q = n->(n<<1-1)<<1;
c = n->12*n-5;
d = n->n*(n<<1-1)<<1;
s = 5*zeta(3)/3;
F = [a,b,p,q,c,d];
*/
Making a close analysis of the nested hypergeometric series W and partial sums W(n1,n2) I have found the binary splitting relationships,
Write the inner hypergeometric sum in W(n1,n2) as
Z(n1,n2) = SUM(m=n1,n2-1,c(m)/d(m) * PROD(i=n1,m,f(i)/g(i)))
we have
W(n1,n2) = = SUM(n=n1,n2-1,a(n)/b(n) * PROD(k=n1,n,p(k)/q(k)) * Z(n1,n+1))
The algorithm is a deeper variation of the previous one. We have now 8 polynomial functions a(n), b(n), p(n), q(n), c(n), d(n), f(n), g(n). Set these products and sums to be computed by binary splitting
P = p(n1) ... p(n2-1)
Q = q(n1) ... q(n2−1)
B = b(n1) ... b(n2-1)
T = B Q S
D = d(n1) ... d(n2-1)
F = f(n1) ... f(n2-1)
G = g(n1) ... g(n2-1)
C = D G Z
V = D B Q G W
If n2 - n1 =< 4 these values are computed directly. If n2 - n1 > 4 they are computed recursively by binary splitting. Choose an index nm in the middle of n1 and n2, compute the components Pl, Ql, Bl , Tl, Dl, Cl, Vl, Fl, Gl belonging to the interval n1 =< n < nm, compute the components Pr, Qr , Br, Tr, Dr, Cr, Vr, Fr, Gr belonging to the interval nm =< n < n2 and set these products and sums
P = Pl Pr
Q = Ql Qr
B = Bl Br
T = Br Qr Tl + Bl Pl Tr
D = Dl Dr
F = Fl Fr
G = Gl Gr
C = Cl Dr Gr + Cr Dl Fl
V = Dr Br Qr Gr Vl + Dr Cl Bl Pl Gr Tr + Dl Bl Pl Fl Vr
Using auxiliary variables and factorizing, these 27 big integer products can be reduced to just 19. Finally, this algorithm is applied to n1 = 0 and n2 = nmax = O(N), and final floating point divisions are performed. Algorithm provides all 3 sums
S = T / (B Q)
Z = C / (D G)
W = V / (B Q D G)
I will code and test this algorithm to complement this answer. Many convergence acceleration methods (CAM) applied to some slowly convergent series have the structure of series W (for example, some classical CAMs like Salzer's, Gustavson's, sumalt() from Pari GP -Cohen, Rodriguez, Zagier-, Weniger's transformations and several Levin-type CAMs). I believe that the merge of BinSplit and Levin-type sequence transformations should provide a strong boost to this topic. We will see.

Mathematica Code with Module and If statement

Can I simply ask the logical flow of the below Mathematica code? What are the variables arg and abs doing? I have been searching for answers online and used ToMatlab but still cannot get the answer. Thank you.
Code:
PositiveCubicRoot[p_, q_, r_] :=
Module[{po3 = p/3, a, b, det, abs, arg},
b = ( po3^3 - po3 q/2 + r/2);
a = (-po3^2 + q/3);
det = a^3 + b^2;
If[det >= 0,
det = Power[Sqrt[det] - b, 1/3];
-po3 - a/det + det
,
(* evaluate real part, imaginary parts cancel anyway *)
abs = Sqrt[-a^3];
arg = ArcCos[-b/abs];
abs = Power[abs, 1/3];
abs = (abs - a/abs);
arg = -po3 + abs*Cos[arg/3]
]
]
abs and arg are being reused multiple times in the algorithm.
In a case where det > 0 the steps are
po3 = p/3;
b = (po3^3 - po3 q/2 + r/2);
a = (-po3^2 + q/3);
abs1 = Sqrt[-a^3];
arg1 = ArcCos[-b/abs1];
abs2 = Power[abs1, 1/3];
abs3 = (abs2 - a/abs2);
arg2 = -po3 + abs3*Cos[arg1/3]
abs3 can be identified as A in this answer: Using trig identity to a solve cubic equation
That is the most salient point of this answer.
Evaluating symbolically and numerically may provide some other insights.
Using demo inputs
{p, q, r} = {-2.52111798, -71.424692, -129.51520};
Copyable version of trig identity notes - NB a, b, p & q are used differently in this post
Plot[x^3 - 2.52111798 x^2 - 71.424692 x - 129.51520, {x, 0, 15}]
a = 1;
b = -2.52111798;
c = -71.424692;
d = -129.51520;
p = (3 a c - b^2)/3 a^2;
q = (2 b^3 - 9 a b c + 27 a^2 d)/27 a^3;
A = 2 Sqrt[-p/3]
A == abs3
-(b/3) + A Cos[1/3 ArcCos[
-((b/3)^3 - (b/3) c/2 + d/2)/Sqrt[-(-(b^2/9) + c/3)^3]]]
Edit
There is also a solution shown here
TRIGONOMETRIC SOLUTION TO THE CUBIC EQUATION, by Alvaro H. Salas
Clear[a, b, c]
1/3 (-a + 2 Sqrt[a^2 - 3 b] Cos[1/3 ArcCos[
(-2 a^3 + 9 a b - 27 c)/(2 (a^2 - 3 b)^(3/2))]]) /.
{a -> -2.52111798, b -> -71.424692, c -> -129.51520}
10.499

Low-Rank Approximation using Frobenious Norm Tolerance

I would love some help with an algorithm I've working on. My specific problem is in the while loop of the algorithm.
What I want the algorithm to do is to sequentially add a singular value in Sk(until the desired TOL is achieved) in the diagonal while making the rest of the matrix 0. The desired goal is to do this to greyscale images.
I can only get 2x2 cycles.
here is the code:
A = rand(5)*30;
[M N] = size(A);
[U S V] = svds(A);
% r = rank(A);
Sn = S(1,1);
Sk = blkdiag(Sn,zeros(N-1));
Ak = U*Sk*V;
X = A - Ak;
F = norm(X,'fro');
tol = 10;
i = 2;
while F > tol
Snk = S(i,i);
Snew = diag([Sn;Snk]);
Sk = blkdiag(Snew,zeros(N-2));
Ak = U*Sk*V';
F = norm(A-Ak,'fro');
i = i + 1;
end

Ho do I make this code segment faster in matlab?

function [D] = distChiSq( W, X )
%%% find the Chi2Dist distance between each weight vector and X
% W is nxd
m = size(W,1); n = size(X,1);
k = size(W,2);
mOnes = ones(1,m); D = zeros(m,n);
for i=1:n
Xi = X(i,:); XiRep = Xi( mOnes, : );
s = XiRep + W; /************/
d = XiRep - W; /************/
D(:,i) = sum( d.^2 ./ (s+eps), 2 ); /************/
end
D = D/2;
This is an part from my Chi2 distance calculation between Weight matrix and Data. Marked lines are the most consuming lines of the all code. Is there any way to do it faster in MATLAB?
If data is nxm than s = nxm, d = nxm and D is keeping the distances. n is number of instances and m is number of variables.
Oh, this is so much fun with bsxfun:
s = bsxfun( #plus, permute( X, [1 3 2] ), permute( W, [3 1 2] ) ) + eps;
d = bsxfun( #minus, permute( X, [1 3 2] ), permute( W, [3 1 2] ) ).^2;
D = .5*sum( d./s, 3 );
Alternative to the great answer from Shai:
F = #(a,b) (a-b).^2 ./ (a+b+eps);
D = sum(bsxfun(F, permute(X, [3 1 2]), permute(W, [1 3 2])), 3)/2;

Simple equations solving

Think of a equations system like the following:
a* = b + f + g
b* = a + c + f + g + h
c* = b + d + g + h + i
d* = c + e + h + i + j
e* = d + i + j
f* = a + b + g + k + l
g* = a + b + c + f + h + k + l + m
h* = b + c + d + g + i + l + m + n
...
a, b, c, ... element of { 0, 1 }
a*, b*, c*, ... element of { 0, 1, 2, 3, 4, 5, 6, 7, 8 }
+ ... a normal integer addition
Some of the variables a, b, c... a*, b*, c*... are given. I want to calculate as much other variables (a, b, c... but not a*, b*, c*...) as logically possible.
Example:
given: a = 0; b = 0; c = 0;
given: a* = 1; b* = 2; c* = 1;
a* = b + f + g ==> 1 = 0 + f + g ==> 1 = f + g
b* = a + c + f + g + h ==> 2 = 0 + 0 + f + g + h ==> 2 = f + g + h
c* = b + d + g + h + i ==> 1 = 0 + d + g + h + i ==> 1 = d + g + h + i
1 = f + g
2 = f + g + h ==> 2 = 1 + h ==> h = 1
1 = d + g + h + i ==> 1 = d + g + 1 + i ==> d = 0; g = 0; i = 0;
1 = f + g ==> 1 = f + 0 ==> f = 1
other variables calculated: d = 0; f = 1; g = 0; h = 1; i = 0;
Can anybody think of a way to perform this operations automatically?
Brute force may be possible in this example, but later there are about 400 a, b, c... variables and 400 a*, b*, c*... variables.
This sounds a little like constraint propogation. You might find "Solving every Sudoku Puzzle" a good read to get the general idea.
The problem is NP-complete. Look at the system of equations:
2 = a + c + d1
2 = b + c + d2
2 = a + b + c + d3
Assume that d1,d2,d3 are dummy variables that are only used once and hence add no other constraints that di=0 or di=1. Hence from the first equation follows c=1 if a=0. From the second equation follows c=1 if b=0 and from the third one we get c=0 if a=1 and b=1 and hence we get the relation
c = a NAND b.
Thus we can express any boolean circuit using such a system of equations and therefore the boolean satisfyability problem can be reduced to solving such a system of equations.

Resources