
Testing("Solve");

VerifySolve(Solve(a+x*y==z,x),{x==(z-a)/y});

// check that solving systems of equations works, at least at the
// level of simple back-substitutions
VerifySolve(Solve({a+x*y==z},{x}),{{x==(z-a)/y}});

// check linear systems
VerifySolve(Solve({2*x-2*y+z==(-7),3*x+y+2*z==(-2),5*x+3*y-3*z==(-7)}, {x,y,z}), {x==(-2),y==2,z==1});
VerifySolve(Solve({3*x-2*y+z==1,x-y-z==2,6*x-4*y+2*z==3}, {x,y,z}), {});
VerifySolve(Solve({2*x+3*y==6,4*x+6*y==12}, {x,y}), {x==3-(3*y)/2,y==y});

[
  Local(eq,res);
  eq:={a-b==c,b==c};
  res:=Solve(eq,{a,b});
  Verify(eq Where res,{c==c,c==c});
];

VerifySolve(Solve(a+x*y == z, x), { x == (z-a)/y });

VerifySolve(Solve(x^2-3*x+2, x), { x == 1, x == 2 });

VerifySolve(Solve(2^n == 32, n), { n == Ln(32)/Ln(2) });  
            /* Of course, Ln(32)/Ln(2) = 5 */

VerifySolve(Solve(ArcTan(x^4) == Pi/4, x), { x == 1, x == -1, x == I, x == -I });

VerifySolve(Solve(Exp(x)/(1-Exp(x)) == a, x), {x == Ln(a/(a+1))});
VerifySolve(Solve(Exp(x)/(1-Exp(x)) == a, a), {a == Exp(x)/(1-Exp(x))});

//VerifySolve(Solve(x^5 == 1, x), 
//            { x == 1, x == Exp(2/5*I*Pi), x == Exp(4/5*I*Pi), 
//              x == Exp(-2/5*I*Pi), x == Exp(-4/5*I*Pi)});

VerifySolve(Solve(Sqrt(x) == 1, x),  { x == 1 });
VerifySolve(Solve(Sqrt(x) == -1, x), { });
VerifySolve(Solve(Sqrt(x) == I, x),  { x == -1 });
VerifySolve(Solve(Sqrt(x) == -I, x), { });
VerifySolve(Solve(Sqrt(x) == 0, x),  { x == 0 });


/* The following equations have in fact infinitely many solutions */

VerifySolve(Solve(Sin(x), x), { x == 0, x == Pi });

VerifySolve(Solve(Sin(x), x), { x == 0, x == Pi });

VerifySolve(Solve(Cos(a)^2 == 1/2, a), 
            { a == Pi/4, a == 3/4*Pi, a == -3/4*Pi, a == -Pi/4 });

/* The solution could have nicer form, but it is correct, apart from periodicity */
VerifySolve(Solve(Sin(a*Pi)^2-Sin(a*Pi)/2 == 1/2, a), {a==Pi/(2*Pi),a==-Pi/(6*Pi),a==(Pi+Pi/6)/Pi});

Verify(IsError(), False);

/* This equation can be solved (the solution is x>0), but the current
 * code does not do this. The least we can expect is that no spurious
 * solutions are returned. */
VerifySolve(Solve(0^x == 0, x), {});
Verify(ClearError("Solve'Fails"), True);
Verify(IsError(), False);

/* This equation could be solved using the Lambert W function */
VerifySolve(Solve(x^x == 1, x), {});
Verify(ClearError("Solve'Fails"), True);
Verify(IsError(), False);

/* Another equation which cannot be solved at the moment */
VerifySolve(Solve(BesselJ(1,x), x), {});
Verify(ClearError("Solve'Fails"), True);
Verify(IsError(), False);

/* And another one */
VerifySolve(Solve(Exp(x)+Cos(x) == 3, x), {});
Verify(ClearError("Solve'Fails"), True);
Verify(IsError(), False);

/* This equation could be solved if we knew that x >= 0 */
VerifySolve(Solve(Sqrt(x) == a, x),  { });
Verify(ClearError("Solve'Fails"), True);
Verify(IsError(), False);

/* Test the type-checking mechanism */
VerifySolve(Solve(2*x == 1, 1), {});
Verify(ClearError("Solve'TypeError"), True);
Verify(IsError(), False);

/* This command is clearly nonsense, but it used to send Yacas in an
 * infinite recursion, which should never happen.  Note that 'Differentiate(y)x == 0'
 * is parsed as 'Differentiate(y)(x==0)'. */
VerifySolve(Solve(Differentiate(y)(x == 0), x),  { });
Verify(ClearError("Solve'Fails"), True);
Verify(IsError(), False);

/**********************************************************************/

Testing("PSolve");

/* Linear equations */
Testing("     Linear");

VerifySolve(PSolve(x,x), 0);
VerifySolve(PSolve(x+3*Sin(b)-1,x), 1-3*Sin(b));
VerifySolve(PSolve(2*x-a,x), a/2);
VerifySolve(PSolve(2*x-a,a), 2*x);

/* Quadratic equations */
Testing("     Quadratic");

VerifySolve(PSolve(x^2,x), 0);
VerifySolve(PSolve(4*x^2-1,x), {1/2,-1/2});
VerifySolve(PSolve(x^2+1,x), {I,-I});
VerifySolve(PSolve(x^2-3*x+2,x), {1,2});

/* Cubic equations */
Testing("     Cubic");

VerifySolve(PSolve(x^3,x), 0);
VerifySolve(PSolve(x^3-1,x), {1, Exp(2/3*Pi*I), Exp(-2/3*Pi*I)});
VerifySolve(PSolve(x^3+1,x), {-1, Exp(1/3*Pi*I), Exp(-1/3*Pi*I)});
VerifySolve(PSolve(x^3-3*x^2+2*x,x), {0,2,1});

/* Quartic equations */
Testing("     Quartic");

VerifySolve(PSolve(x^4,x), 0);
VerifySolve(PSolve(16*x^4-1,x), {1/2, -1/2, 1/2*I, -1/2*I});
VerifySolve(PSolve(x^4-x,x), {0, 1, Exp(2/3*Pi*I), Exp(-2/3*Pi*I)});
VerifySolve(PSolve(x^4+x,x), {0, -1, Exp(1/3*Pi*I), Exp(-1/3*Pi*I)});

/* Yacas has difficulties with more complicated equations, like the 
 * biquadratic x^4 - 3*x^2 + 2. */

/* Added the ability to Solve and Where to handle expressions more complex than just variables. 
   One can now Solve for say x[1], or Sin(x) (it only uses a simple comparison for now though).  
   The following test just assures that that will never break.
 */
Verify(Simplify(x[1]-4*x[2]+x[3] Where (Solve({x[1]-4*x[2]+x[3]==0},{x[2]}))),{0});


/*TODO MatrixSolve */

// moved from xSingle_test_solve.mpw
VerifySolve(Solve(3/(x^2+x-2)-1/(x^2-1)-7/(2*(x^2+3*x+2))==0, x), {x==3});
VerifySolve(Solve(3/(x^2+x-2)-1/(x^2-1)==7/(2*(x^2+3*x+2)), x), {x==3});

// moved from xTestSolve.mpw

// Tricky one; the solution should depend on a being 0
// FIXME: the equation leaves the error set to Solve'Fails
//VerifySolve(Solve(a == 0,x),{});

VerifySolve(Solve(0,x),{x==x});
VerifySolve(Solve(x-5,x),{x==5});
VerifySolve(Solve(x-a,x),{x==a});
VerifySolve(Solve(12*x+5==29,x),{x==2});
VerifySolve(Solve(5*x-15==5*(x-3),x),{x==x});
VerifySolve(Solve(5*x-15==5*(x-4),x),{});
VerifySolve(Solve(x^2-4,x),{x==2,x==(-2)});

//VerifySolve(Solve(x^2-a^2,x),{x==a,x==(-a)});

VerifySolve(Solve(2*x^2+9*x==18,x),{x==(-6),x==3/2});
VerifySolve(Solve(5*x^2==25*x,x),{x==0,x==5});
VerifySolve(Solve(2*x/5-x/3==2,x),{x==30});
VerifySolve(Solve(2/x-3/2==7/(2*x),x),{x==(-1)});
VerifySolve(Solve(2/(x-3)-3/(x+3)==12/(x^2-9),x),{});
VerifySolve(Solve(3/(x^2+x-2)-1/(x^2-1)==7/(2*(x^2+3*x+2)),x),{x==3});
VerifySolve(Solve(1+1/x==6/x^2,x),{x==2,x==(-3)});
VerifySolve(Solve(Sqrt(x)-3,x),{x==9});
VerifySolve(Solve(Sqrt(x-3),x),{x==3});
VerifySolve(Solve(Sqrt(x-3)==2,x),{x==7});

//VerifySolve(Solve(Sqrt(2*x)==Sqrt(x+1),x), {x==1});
//VerifySolve(Solve(Sqrt(x)==x,x),{x==1,x==0});
//VerifySolve(Solve(Sqrt(x+2)-2*x==1,x),{x==1/4});
//VerifySolve(Solve(Sqrt(x+2)+2*x==1,x),{x==(5 - Sqrt(41))/8});
//VerifySolve(Solve(Sqrt(9*x^2+4)-3*x==1,x),{x==1/2});

VerifySolve(Solve(Sqrt(x+1)-Sqrt(x)==-2,x),{});

//VerifySolve(Solve(Sqrt(3*x-5)-Sqrt(2*x+3)==-1,x),{x==3});

VerifySolve(Solve(Exp(x)==4,x),{x==Ln(4)});
VerifySolve(Solve(Exp(x)==Abs(a),x),{x==Ln(Abs(a))});
VerifySolve(Solve(Ln(x)==4,x),{x==Exp(4)});
VerifySolve(Solve(Ln(x)==a,x),{x==Exp(a)});
VerifySolve(Solve((x+6)/2-(3*x+36)/4==4,x),{x==-40});
VerifySolve(Solve((x-3)*(x-4)==x^2-2,x),{x==2});
VerifySolve(Solve(a*x-2*b*c==d,x),{x==(2*b*c+d)/a});
VerifySolve(Solve((36-4*x)/(x^2-9)-(2+3*x)/(3-x)==(3*x-2)/(x+3),x),{x==-2});

//VerifySolve(Solve((x^2-1)^(1/3)==2,x),{x==3,x==(-3)});

VerifySolve(Solve(x^4-53*x^2+196==0,x),{x==(-7),x==(-2),x==2,x==7});
VerifySolve(Solve(x^3-8==0,x),{x==2,x==-1+I*Sqrt(3),x==-1-I*Sqrt(3)});

//VerifySolve(Solve(x^(2/3)+x^(1/3)-2==0,x),{x==1,x==(-8)});
//VerifySolve(Solve(Sqrt(x)-(1/4)*x==1,x),{x==4});
//VerifySolve(Solve((1/4)*x-Sqrt(x)==-1,x),{x==4});

VerifySolve(Solve({x-y==1,3*x+2*y==13},{x,y}),{x==3,y==2});
VerifySolve(Solve({x-y-1==0,2*y+3*x-13==0},{x,y}),{x==3,y==2}); 
