%mathpiper,title="xCheckSolution"

//Retract("xCheckSolution",*);
//Retract("CloseEnough",*);

10 # CloseEnough(_expr1,_expr2,_prec) <--
  [
      If(iDebug=True,Tell("CloseEnough",{expr1,expr2,prec}));
      Local(diff,ndiff,ncomp,result);
      diff := expr1 - expr2;
      If(diff != 0 And HasFunc(expr1,Sqrt), diff := RadSimp(expr1-expr2));
      If(diff != 0, diff := Simplify(expr1-expr2));      
      If(iDebug=True,Tell("  ce1",diff));
      If(diff=0,
          result:=True,
          [
              ndiff := Abs(N(diff,prec+1));
              ncomp := N(10^(-prec),prec);
              If(iDebug=True,Tell("  ce2",{ndiff,ncomp,ndiff/ncomp}));
              If(ndiff/ncomp<1,result:=True,result:=False);
          ]
      );
      result;
  ];
  

10 # xCheckSolution( exprs_IsList, _var, solutions_IsList ) <--
  [
      If(iDebug=True,Tell("xCheckSolutionL",{exprs,var,solutions}));
      Local(tests);
      
      tests := Subst(==,ToAtom("-")) (exprs Where solutions);
      If(iDebug,Tell("  1",tests));
      tests := AllSatisfy("IsZero",tests);
  ];

  
12 # xCheckSolution( _expr, _var, solution_IsList ) <--
  [
      If(iDebug=True,Tell("xCheckSolution1",{expr,var,solution}));
      Local(expr0,result,s,r);
      If( IsEquation(expr),
          Bind(expr0,EquationLeft(expr)-EquationRight(expr)),
          Bind(expr0,expr)
      );
      result := {};
      ForEach(s,solution) 
        [
            If(iDebug=True,Tell("  cs1",s));
            r := ( expr0 Where s );
            If(iDebug=True,Tell("    cs2",{expr0,r}));
            If(r=0,Push(result,s),If(CloseEnough(r,0,10),Push(result,s)));
        ];
        If(iDebug=True,Tell("  cs4",result)); 
        Reverse(result);
  ];
  
  
20 # xCheckSolution( _expr, _var, _solution ) <-- False;

%/mathpiper



%mathpiper_docs,name="xCheckSolution",categories="User Functions;Solvers (Symbolic)",access="experimental"

*CMD xCheckSolution --- Check the validity of solutions returned by the {xSolve} function.
*STD
*CALL
	xCheckSolution(expr,var,solution)

*PARMS

{expr}     -- a mathematical expression, or List of simultaneous equations
{var}      -- a varible identifier, or List of variables
{solution} -- a List containing solutions to the equation(s).


*DESC

The function {xSolve} will attempt to find solutions to the equation
{expr}, if {expr} is an actual equatio), or to the equivalent equation
represented by {expr==0} if {expr} is NOT an equation.  
If expr is a List of simultaneous linear equations, {xSolve} will
attempt to solve the system.

Solutions returned by {xSolve} will be in the form of a List, such as
{{var==something,var==something_else}}.

For certain types of expressions or equation, {xSolve} might return
invalid solutions as well as valid ones in the output List.  To check
the list of solutions, call the function xCheckSolutions().  This function
will return a list containing only the valid solutions from among those
in the list (if any).  If none of the "solutions" is valid, this 
function will return the empty list.

*E.G.

In> ss1 := xSolve(x^2==4,x)

Result: {x==2,x==(-2)}

In> xCheckSolution(x^2==4,x,ss1)

Result: {x==2,x==(-2)}

In> xCheckSolution(x^2==4,x,{x==2,x==3})   // Deliberately incorrect

Result: {x==2}

%/mathpiper_docs



