/*		SIMEQ		  19.2.81  */
/*****************************************/
/* SIMULTANEOUS EQUATIONS ROUTINES*/
/*****************************************/

/*simultaneous solution with messages*/
simsolve(Eqns,Us,Ans)
	:- trace('Simultaneously solving : %cFor %t.\n',[Eqns,Us],1),
	   simsolve1(Eqns,Us,Ans1), tidy(Ans1,Ans),
           trace('\nFinal Answers are : %e', [Ans],1),
	   !.


/* Solve conjunction of equations */
simsolve1(EqnsA & EqnsB,[X|Unks], Ans1) :- !,
	pick_xeqn(EqnsA & EqnsB,X,XEqn,Rest),
	solve(XEqn,X,Ans),
	distribute(Ans,Rest,Eqns1),
	simsolve2(Eqns1,Unks,Ans1).



/*single equation*/
simsolve1(A=B, [U], Ans) :- !, solve(A=B,U,Ans).


/*basis case*/
simsolve1(true,[],true) :- !.

/*Pick equation to solve for x, and return the remainder */
pick_xeqn(EqnC,X,XEqn,RestC) :-  !,
	andtodot(EqnC,EqnL),
	sublist(contains(X),EqnL,XEqnL),
	subtract(EqnL,XEqnL,NonXRestL),
	select(XEqn,XEqnL,XRestL),
	append(XRestL,NonXRestL,RestL),
	dottoand(RestL,RestC).

/* Distribute Or over And */
distribute(Sub1 # Sub2, Exp, Ans1 # Ans2) :- !, % disjunction case
	distribute(Sub1,Exp,Ans1),
	distribute(Sub2,Exp,Ans2).

distribute(Sub, Exp, Sub & Ans) :- !,	% conjunction or single equation case
	subst_mesg(Sub,Exp,Ans).


/* Call simsolve1 recursively and substitute back */
simsolve2(Eqns1 # Eqns2, Unks, Ans1 # Ans2) :- !,	% Solve disjunction
	simsolve2(Eqns1,Unks,Ans1),
	simsolve2(Eqns2,Unks,Ans2).

simsolve2(X=Ans1 & Eqns, Unks, Ans3) :- !,	% Discount already solved equation
	simsolve1(Eqns, Unks, Ans2),
	trace('Substituting back in %t solution\n',[X],1),
	distribute(Ans2,X=Ans1,Ans3).

/* Problems
	2. Return particular solutions; alternates on backtracking.
	4. Reject silly answers as required by Cardan. (??)
*/
