/* LADYBUG is a 'Buggy'-type program for the Linear Algebra Domain */ instructions :- nl, write('Welcome to LADYBUG. The format if very simple.'), nl, write('type "show." to find the status of the tracer.'), nl, write('Turn it off for now. Next type "protocol." and'), nl, write('choose a number from 1 to 6 (0 for standard protocol)'), nl, write('Then just type "begin." once for each equation'), nl, write('you"d like LADYBUG to solve. Enjoy...'). begin :- nl, write('Please enter an equation (q to quit)'),nl, read(Eqn), protocol(M), solve(M,Eqn). /* PROTOCOL 0: no malrule -- correct algebraic manipulation */ solve(0,Lhs=Rhs) :- present('solving ',Lhs,Rhs), !, cattract(Lhs,Rhs,Lhs2,Rhs2), iattract(Lhs2,Rhs2,Lhs3,Rhs3), consolidate(Lhs3,Sum_coeffs), present(lhs_consolidate,Sum_coeffs*x,Rhs3), consolidate(Rhs3,Sum_integers), present(rhs_consolidate,Sum_coeffs*x,Sum_integers), /* equation should now be in form: C*x = I */ isolate(Sum_coeffs * x,Sum_integers,Ans), present('isolate ',x,Ans), nl,write(' x = '),write(Ans),nl. /* PROTOCOL 1: student forgets to change signs when attracting coeffs */ solve(1,Lhs=Rhs) :- present('solving ',Lhs,Rhs), !, malcattract(Lhs,Rhs,Lhs2,Rhs2), iattract(Lhs2,Rhs2,Lhs3,Rhs3), consolidate(Lhs3,Sum_coeffs), present(lhs_consolidate,Sum_coeffs*x,Rhs3), consolidate(Rhs3,Sum_integers), present(rhs_consolidate,Sum_coeffs*x,Sum_integers), /* equation should now be in form: C*x = I */ isolate(Sum_coeffs * x,Sum_integers,Ans), present('isolate ',x,Ans), nl,write(' x = '),write(Ans),nl. /* PROTOCOL 2: student forgets to change signs when attracting integers */ solve(2,Lhs=Rhs) :- present('solving ',Lhs,Rhs), !, cattract(Lhs,Rhs,Lhs2,Rhs2), maliattract(Lhs2,Rhs2,Lhs3,Rhs3), consolidate(Lhs3,Sum_coeffs), present(lhs_consolidate,Sum_coeffs*x,Rhs3), consolidate(Rhs3,Sum_integers), present(rhs_consolidate,Sum_coeffs*x,Sum_integers), /* equation should now be in form: C*x = I */ isolate(Sum_coeffs * x,Sum_integers,Ans), present('isolate ',x,Ans), nl,write(' x = '),write(Ans),nl. /* PROTOCOL 3: student never changes signs when bringing terms across the equality sign */ solve(3,Lhs=Rhs) :- present('solving ',Lhs,Rhs), !, malcattract(Lhs,Rhs,Lhs2,Rhs2), maliattract(Lhs2,Rhs2,Lhs3,Rhs3), consolidate(Lhs3,Sum_coeffs), present(lhs_consolidate,Sum_coeffs*x,Rhs3), consolidate(Rhs3,Sum_integers), present(rhs_consolidate,Sum_coeffs*x,Sum_integers), /* equation should now be in form: C*x = I */ isolate(Sum_coeffs * x,Sum_integers,Ans), present('isolate ',x,Ans), nl,write(' x = '),write(Ans),nl. /* PROTOCOL 4: at last step (isolate), student ignores coeff. and gives answer as the integer on RHS, thereby avoiding dividing through. */ solve(4,Lhs=Rhs) :- present('solving ',Lhs,Rhs), !, cattract(Lhs,Rhs,Lhs2,Rhs2), iattract(Lhs2,Rhs2,Lhs3,Rhs3), consolidate(Lhs3,Sum_coeffs), present(lhs_consolidate,Sum_coeffs*x,Rhs3), consolidate(Rhs3,Sum_integers), present(rhs_consolidate,Sum_coeffs*x,Sum_integers), /* N.B. any value of Sum_coeffs is ignored */ isolate(x,Sum_integers,Ans), present('mal isolate ',x,Ans), nl,write(' x = '),write(Ans),nl. /* PROTOCOL 5: in last step (isolate), student divides through "backwards" or inversely */ solve(5,Lhs=Rhs) :- present('solving ',Lhs,Rhs), !, cattract(Lhs,Rhs,Lhs2,Rhs2), iattract(Lhs2,Rhs2,Lhs3,Rhs3), consolidate(Lhs3,Sum_coeffs), present(lhs_consolidate,Sum_coeffs*x,Rhs3), consolidate(Rhs3,Sum_integers), present(rhs_consolidate,Sum_coeffs*x,Sum_integers), /* N.B. effect achieved by switching Sum_coeffs and Sum_integers */ isolate(Sum_integers * x,Sum_coeffs,Ans), present('mal isolate ',x,Ans), nl,write(' x = '),write(Ans),nl. /* PROTOCOL 6: student never attracts like terms to separate sides. He immediately collects by adding up all numbers on LHS regardless of function (coeff or free integer) and then does the same with the RHS. He then proceeds to isolate properly */ solve(6,Lhs=Rhs) :- present('solving ',Lhs,Rhs), !, consolidate(Lhs,Sum_coeffs), present(lhs_consolidate,Sum_coeffs*x,Rhs), consolidate(Rhs,Sum_integers), present(rhs_consolidate,Sum_coeffs*x,Sum_integers), /* equation should now be in form: C*x = I */ isolate(Sum_coeffs * x,Sum_integers,Ans), present('isolate ',x,Ans), nl,write(' x = '),write(Ans),nl. /* CATTRACT will attract all C*x terms to LHS */ cattract(Lhs,Rhs,Nlhs,Nrhs) :- cmatch(Rhs,C,Rest), 0 =\= C,!, chng_sign(C,Negc), ccombine(Lhs,Negc,Combo), present('coeff_attract ',Combo,Rest), cattract(Combo,Rest,Nlhs,Nrhs). cattract(Lhs,Rhs,Lhs,Rhs). /* MALCATTRACT will attrct all C*x terms to LHS but won't change signs */ malcattract(Lhs,Rhs,Nlhs,Nrhs) :- cmatch(Rhs,C,Rest), 0 =\= C,!, /* N.B. no sign change here */ ccombine(Lhs,C,Combo), present('malcoef_attract',Combo,Rest), malcattract(Combo,Rest,Nlhs,Nrhs). malcattract(Lhs,Rhs,Lhs,Rhs). /* IATTRACT will attract all free integers to the RHS */ iattract(Lhs,Rhs,Nlhs,Nrhs) :- imatch(Lhs,I,Rest), 0 =\= I,!, chng_sign(I,Negi), icombine(Rhs,Negi,Combo), present(integer_attract,Rest,Combo), iattract(Rest,Combo,Nlhs,Nrhs). iattract(Lhs,Rhs,Lhs,Rhs). /* MALIATTRACT will attract free integers to RHS forgetting to change signs */ maliattract(Lhs,Rhs,Nlhs,Nrhs) :- imatch(Lhs,I,Rest), 0 =\= I,!, icombine(Rhs,I,Combo), present(malint__attract,Rest,Combo), maliattract(Rest,Combo,Nlhs,Nrhs). maliattract(Lhs,Rhs,Lhs,Rhs). /* IMATCH will parse free-standing integers given one side of equation */ imatch(X + I,I,X) :- integer(I),!. imatch(X - I,-I,X) :- integer(I),!. imatch(-I + X,-I,X) :- integer(I),!. imatch(-I - X,-I,-X) :- integer(I),!. imatch(I + X,I,X) :- integer(I),!. imatch(I - X,I,-X) :- integer(I),!. imatch(X + Y,I,Z + Y) :- imatch(X,I,Z). imatch(X - Y,I,Z - Y) :- imatch(X,I,Z). imatch(X,0,X). /* CMATCH will parse coefficients given one side of equation */ cmatch(X + C*x,C,X) :- integer(C),!. cmatch(X - C*x,-C,X) :- integer(C),!. cmatch(C*x + X,C,X) :- integer(C),!. cmatch(C*x - X,C,-X) :- integer(C),!. cmatch(-C*x + X,-C,X) :- integer(C),!. cmatch(-C*x - X,-C,-X) :- integer(C),!. cmatch(X + Y,C,Z + Y) :- cmatch(X,C,Z). cmatch(X - Y,C,Z - Y) :- cmatch(X,C,Z). cmatch(X,0,X). /* CHNG_SIGN will do just that */ chng_sign(X,Y) :- Y is - X. /* COMBINE, given one side of equation and an atom, will add the atom, whether integer or C*x, positive or negative, to the side. */ ccombine(X,0,X). /* to allow for the 'drop through' case */ ccombine(X,- C,X - C*x). ccombine(X,C,X + C*x). icombine(X,0,X). icombine(X,I,X + I). /* CONSOLIDATE,given a side of an equation Side, will add all integers, whether free-integers, coefficients, or both, and return the sum as Sum */ consolidate(-C*x,-C) :- !. consolidate( C*x, C) :- !. consolidate(Side,Sum) :- cmatch(Side,C,Rest), 0 =\= C,!, consolidate(Rest + C,Sum). consolidate(Side,Sum) :- imatch(Side,I,Rest), 0 =\= I,!, Newside is Rest + I, consolidate(Newside,Sum). consolidate(Sum,Sum). /* ISOLATE divides through by coeff, leaving ans in manageable form */ isolate(0 * x,I,undefined) :- !. isolate(C * x,I,Ans) :- integer(C),integer(I), 0 =:= (I mod C),!, Ans is I / C. isolate(C * x,I,I / C). isolate(x,I,I). /* PRESENT is a simple display routine */ present(Rule,Lhs,Rhs) :- show(on),!, write(Rule),write(' : '), write(Lhs),write(' = '),write(Rhs),nl. present(A,B,C). protocol :- protocol_now(M), write('current protocol is '),write(M),nl, write('Desired protocol number = '),nl, read(N), N < 7,!, retract(protocol(_)), asserta(protocol(N)), protocol_now(O), nl,write('Current protocol is now '),write(O),nl, offersample(O). protocol_now(M) :- protocol(M),!. protocol_now(0) :- asserta(protocol(0)),!. show :- show_now(S), write('show is presently '),write(S),nl, write('Desired status (on./off.) '),nl, read(T), retract(show(_)), asserta(show(T)), show_now(U), nl,write('Show is now turned '),write(U),nl. show_now(S) :- show(S),!. show_now(off) :- asserta(show(off)),!. offersample(0) :- nl, write('No malrule -- Standard Algebraic Manipulation'). offersample(1) :- nl, write('5 + 4*x = 1*x + 20 ? The answer is 3.'). offersample(2) :- nl, write('3*x - 1 + 3*x = 4*x - 7 ? The answer is -4.'). offersample(3) :- nl, write('2*x + 3 = 1*x + 6 ? The answer is 3.'). offersample(4) :- nl, write('3*x = 2*x + 7 ? The answer is 7.'). offersample(5) :- nl, write('-7 + 3*x = -1*x - 3 ? The answer is 1.'). offersample(6) :- nl, write('3*x - 2 = 2*x + 2 ? The answer is 4').