/*		 SIMEQ		15.5.81  */
/*****************************************/
/* SIMULTANEOUS EQUATIONS ROUTINES*/
/*****************************************/

/* Sugar for old type simsolve - assume that general solution required */
simsolve(Eqns,Unks,Ans) :- simsolve(Eqns,Unks,Ans,gen).


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



/* Solve conjunction of equations for set of unknowns */
simsolve1(Eqns, [], Eqns,Type).		/* no unknowns to solve for. */

simsolve1(Eqns, [X|Unks], Ans1,Type) :-		/* regular case */
	pick_xeqn(Eqns,X,XEqn,Rest),
	solve(XEqn,X,Ans),
	distribute(Ans,Rest,Eqns1),
	simsolve2(Eqns1,Unks,Ans1,Type).


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

/* Distribute Or over And */
distribute(Sub1 v Sub2, Exp, Ans1 v 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 */
/* Solve disjunction  */
simsolve2(Eqns1 v Eqns2, Unks, Ans1 v Ans2,gen) :- !,	/* general solution wanted */
	simsolve2(Eqns1,Unks,Ans1,gen),
	simsolve2(Eqns2,Unks,Ans2,gen).

simsolve2(Eqns1 v Eqns2, Unks, Ans1, part) :-	/* particular solution wanted */
	simsolve2(Eqns1,Unks,Ans1,part).

simsolve2(Eqns1 v Eqns2, Unks, Ans2, part) :-	/* particular solution wanted */
	simsolve2(Eqns2,Unks,Ans2,part).


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

/* Failure message */
fail_mess(X) :- !,
	trace('No equations containing %t\n',[X],1), fail.


/* Problems
	4. Reject silly answers as required by Cardan. (??)
*/
