PROLOG
Student Advisor Expert System
by Shuda Li
% Student Advisor Expert System % Author: Li Shuda % Date:5/27/04 % Design: Provide advice for internatial student who want % to apply to an American Graduate Program. test:- solve(improve(X),CF). solve(Goal, CF) :- retractall(known(_,_)), print_instructions, solve(Goal, CF, [], 20), write(Goal), write(' was concluded with certainty '), write(CF), nl,nl, build_proof(Goal, _, Proof),nl, write('The proof is '),nl,nl, write_proof(Proof, 0), nl,nl, fail. % Case 1: truth value of goal is already known solve(Goal, CF, _, Threshold) :- known(Goal, CF),!, above_threshold(CF, Threshold). % Case 2: negated goal solve( not(Goal), CF, Rules, Threshold) :- !, invert_threshold(Threshold, New_threshold), solve(Goal, CF_goal, Rules, New_threshold), negate_cf(CF_goal, CF). % Case 3: conjunctive goals solve((Goal_1,Goal_2), CF, Rules, Threshold) :- !, solve(Goal_1, CF_1, Rules, Threshold), above_threshold(CF_1, Threshold), solve(Goal_2, CF_2, Rules, Threshold), above_threshold(CF_2, Threshold), and_cf(CF_1, CF_2, CF). %fail. %Case 4: backchain on a rule in knowledge base solve(Goal, CF, Rules, Threshold) :- rule((Goal :- (Premise)), CF_rule), solve(Premise, CF_premise, [rule((Goal :- Premise), CF_rule)|Rules], Threshold), rule_cf(CF_rule, CF_premise, CF), above_threshold(CF, Threshold). %Case 5: fact assertion in knowledge base solve(Goal, CF, _, Threshold) :- rule(Goal, CF), above_threshold(CF, Threshold). % Case 6: ask user solve(Goal, CF, Rules, Threshold) :- askable(Goal), askuser(Goal, CF, Rules),!, assert(known(Goal, CF)), above_threshold(CF, Threshold). % Case 7A: All else fails, see if goal can be solved in prolog. %solve(Goal, 100, _, _) :- % call(Goal). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% % Certainty factor predicates. % Currently, these implement a variation of % the MYCIN certainty factor algebra. % The certainty algebra may be changed by modifying % these predicates. % negate_cf/2 % argument 1 is a certainty factor % argument 2 is the negation of that certainty factor negate_cf(CF, Negated_CF) :- Negated_CF is -1 * CF. % and_cf/3 % arguments 1 & 2 are certainty factors of conjoined predicates % argument 3 is the certainty factor of the conjunction and_cf(A, B, A) :- A== 0,A >0, A =< B. and_cf(A, B, A) :- multiply(A,B,C), C >= 0,A <0, A >= B. and_cf(A, B, 0) :- multiply(A,B,C), C < 0. and_cf(A, B, B) :- multiply(A,B,C), C >= 0,A >0, A >= B. and_cf(A, B, B) :- multiply(A,B,C), C >= 0,A <0, A =< B. multiply(A,B,C):- C is A*B. */ %rule_cf/3 % argument 1 is the confidence factor given with a rule % argument 2 is the confidence inferred for the premise % argument 3 is the confidence inferred for the conclusion rule_cf(CF_rule, CF_premise, CF) :- CF is CF_rule * CF_premise/100. %above_threshold/2 % argument 1 is a certainty factor % argument 2 is a threshold for pruning % % If the threshold, T, is positive, assume we are trying to % prove the goal true. Succeed if CF >= T. % % If T is negative, assume we are trying to prove the goal % false. Succeed if CF <= T. above_threshold(CF, T) :- T >= 0, CF >= T. above_threshold(CF, T) :- T < 0, CF =< T. /* above_threshold(CF, T) :- T >= 0, CF>=0,CF >= T. above_threshold(CF, T) :- T < 0, CF<0,CF =< T. above_threshold(CF, T) :- T < 0, CF>=0, invert_threshold(T, New_T), above_threshold(CF, New_T) . above_threshold(CF, T) :- T > 0, CF=<0, invert_threshold(CF, New_CF), above_threshold(New_CF, T) . */ %invert_threshold/2 % argument 1 is a threshold % argument 2 is that threshold inverted to account for a % negated goal. % % If we are trying to prove not(p), then we want to prove p false. % Consequently, we should prune proofs of p if they cannot prove it % false. This is the role of threshold inversion. invert_threshold(Threshold, New_threshold) :- New_threshold is -1 * Threshold. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%% % Predicates to handle user interactions. As is typical, these % constitute the greatest bulk of the program. % % askuser/3 % argument 1 is a goal whose truth is to be asked of the user. % argument 2 is the confidence the user has in that goal % argument 3 is the current rule stack (used for why queries). % % askuser prints the query, followed by a set of instructions. % it reads the response and calls respond/4 to handle that response askuser(Goal, CF, Rules) :- nl,write('User query:'), write(Goal), nl, write('? '), read(Answer), respond(Answer,Goal, CF, Rules). %respond/4 % argument 1 is the user response % argument 2 is the goal presented to the user % argument 3 is the CF obtained for that goal % argument 4 is the current rule stack (used for why queries). % % The basic scheme of respond/4 is to examine the response and return % the certainty for the goal if possible. % If the response is a why query, how query, etc., it processes the query % and then calls askuser to re prompt the user. % Case 1: user enters a valid confidence factor. %respond(CF, _, CF, _) :- % number(CF),%test whether CF is a number. if CF is a number,return true. % CF =< 100, CF >= -100. % Case 2: user enters 'n' for no. Return a confidence factor of -1.0 respond(n, _, -100, _). % Case 3: user enters 'y' for yes. Return a confidence factor of 1.0 respond(y, _, 100, _). % Case 4: user enters a pattern that matches the goal. This is useful if % the goal has variables that need to be bound. respond(Goal, Goal, CF, _) :- write('Enter confidence in answer'), nl, write('?'), read(CF). % Case 5: user enters a why query respond(why, Goal, CF, [Rule|Rules]) :- write_rule(Rule), askuser(Goal, CF, Rules). respond(why, Goal, CF, []) :- write('Back to top of rule stack.'), askuser(Goal, CF, []). % Case 6: User enters a how query. Build and print a proof respond(how(X), Goal, CF, Rules) :- build_proof(X, CF_X, Proof),!, write(X), write(' was concluded with certainty '), write(CF_X), nl,nl, write('The proof is '),nl,nl, write_proof(Proof, 0), nl,nl, askuser(Goal, CF, Rules). % User enters how query, could not build proof respond(how(X), Goal, CF, Rules):- write('The truth of '), write(X), nl, write('is not yet known.'), nl, askuser(Goal, CF, Rules). % Case 7: User asks for the rules that conclude a certain predicate respond(rule(X), _, _, _) :- write('The following rules conclude about '), write(X),nl,nl, rule((X :- Premise), CF), write(rule((X :- Premise), CF)), nl, fail. respond(rule(_),Goal, CF, Rules) :- askuser(Goal, CF, Rules). % Case 8: User asks for help. respond(help, Goal, CF, Rules) :- print_instructions, askuser(Goal, CF, Rules). %Case 9: User wants to quit. respond(quit,_, _, _) :- quit. %Case 11: Verbal respond(Answer,what_is_your_score_of_verbal_section_in_gre_general_test,CF,_):- Answer=<500, CF is (500-Answer)*100/300/2.0+50. respond(Answer,what_is_your_score_of_verbal_section_in_gre_general_test,CF,_):- Answer>500, CF is (500-Answer)*100/300/2.0-50. %Case 12: Writing respond(Answer,what_is_your_score_of_analytical_writing_section_in_gre_general_test,CF,_):- Answer=<4.0, CF is (4.0-Answer) *100/2/2.0+50. respond(Answer,what_is_your_score_of_analytical_writing_section_in_gre_general_test,CF,_):- Answer>4.0, CF is (4.0-Answer) *100/2/2.0-50. %Case 13: listening_comprehension respond(Answer,what_is_your_score_of_listening_comprehension_in_toefl,CF,_):- Answer=<55, CF is (55-Answer) *100/13/2+50. respond(Answer,what_is_your_score_of_listening_comprehension_in_toefl,CF,_):- Answer>55, CF is (55-Answer) *100/20/2-50. %Case 14: reading_comprehension respond(Answer,what_is_your_score_of_reading_comprehension_in_toefl,CF,_):- Answer=<60, CF is (60-Answer) *100/8/2+50. respond(Answer,what_is_your_score_of_reading_comprehension_in_toefl,CF,_):- Answer>60, CF is (60-Answer) *100/20/2-50. %Case 13: grammar respond(Answer,what_is_your_score_of_grammar_in_toefl,CF,_):- Answer=<60, CF is (60-Answer) *100/8/2+50. respond(Answer,what_is_your_score_of_grammar_in_toefl,CF,_):- Answer>60, CF is (60-Answer) *100/20/2-50. %Case 14: what_is_your_average_score_in_all_courses respond(Answer,what_is_your_average_score_in_all_courses,CF,_):- Answer=<3.5, CF is (3.5-Answer) *100/0.5/2+50. respond(Answer,what_is_your_average_score_in_all_courses,CF,_):- Answer>3.5, CF is (3.5-Answer) *100/2.5/2-50. %Case 15: what_is_your_average_score_in_major_courses_in_last_two_years respond(Answer,what_is_your_average_score_in_major_courses_in_last_two_years,CF,_):- Answer=<3.9, CF is (3.9-Answer) *100/0.1/2+50. respond(Answer,what_is_your_average_score_in_major_courses_in_last_two_years,CF,_):- Answer>3.9, CF is (3.9-Answer) *100/2.5/2-50. %Case 10: Unrecognized input respond(_, Goal,CF, Rules) :- write('Unrecognized response.'),nl, askuser(Goal, CF, Rules). %build_proof/3 % argument 1 is the goal being traced. % argument 2 is the CF of that goal % argument 3 is the proof tree % % build_proof does not do threshold pruning, so it can show % the proof for even goals that would not succeed. build_proof(Goal, CF, ((Goal,CF) :- given)) :- known(Goal, CF),!. build_proof(not(Goal), CF, not(Proof)) :- !, build_proof(Goal, CF_goal, Proof), negate_cf(CF_goal, CF). build_proof((Goal_1, Goal_2), CF, (Proof_1, Proof_2)) :- !, build_proof(Goal_1, CF_1, Proof_1), build_proof(Goal_2, CF_2, Proof_2), and_cf(CF_1, CF_2, CF). build_proof(Goal, CF, ((Goal,CF) :- Proof)) :- rule((Goal :- (Premise)), CF_rule), build_proof(Premise, CF_premise, Proof), rule_cf(CF_rule, CF_premise, CF). build_proof(Goal, CF, ((Goal, CF):- fact)) :- rule(Goal, CF). %build_proof(Goal, 1, ((Goal, 1):- call)) :- % call(Goal). % write_proof/2 % argument 1 is a portion of a proof tree % argument 2 is the depth of that portion (for indentation) % % writes out a proof tree in a readable format write_proof(((Goal,CF) :- given), Level) :- indent(Level), write(Goal), write(' CF= '), write(CF), write(' was given by the user'), nl,!. write_proof(((Goal, CF):- fact), Level) :- indent(Level), write(Goal), write(' CF= '), write(CF), write(' was a fact in the knowledge base'), nl,!. write_proof(((Goal, CF):- call), Level) :- indent(Level), write(Goal), write(' CF= '), write(CF), write(' was proven by a call to prolog'), nl,!. write_proof(((Goal,CF) :- Proof), Level) :- indent(Level), write(Goal), write(' CF= '), write(CF), write(' :-'), nl, New_level is Level + 1, write_proof(Proof, New_level),!. write_proof(not(Proof), Level) :- indent(Level), write('not'),nl, New_level is Level + 1, write_proof(Proof, New_level),!. write_proof((Proof_1, Proof_2), Level) :- write_proof(Proof_1, Level), write_proof(Proof_2, Level),!. % indent/1 % argument 1 is the number of units to indent indent(0). indent(I) :- write(' '), I_new is I - 1, indent(I_new). %print_instructions/0 % Prints all options for user responses print_instructions :- write(' STUDENT ADVISOR FOR GETTING ADMISSIONS FROM U.S. GRADUATE SCHOOL'),nl, write(' (using Expert-System Architecture with uncertain reasoning) '),nl,nl, write(' Responser must have already acquired an bachelor degree and at least '),nl, write(' bear some research experience. Additionally, TOEFL and GRE score is '),nl, write(' required. '), nl,nl, write(' Goal, where Goal is a pattern that will unify with the query'), nl, write(' why.'),nl, write(' how(X), where X is a goal'),nl, write(' rule(X) to display all rules that conclude about X.'),nl, write(' quit, to terminate consultation'),nl, write(' help, to print this message'), nl. % write_rule/1 % argument 1 is a rule specification % writes out the rule in a readable format write_rule(rule((Goal :- (Premise)), CF)) :- write(Goal), write('if'), nl, write_premise(Premise),nl, write('CF = '), write(CF), nl. write_rule(rule(Goal, CF)) :- write(Goal),nl, write('CF = '), write(CF), nl. % write_premise % argument 1 is a rule premise % writes it in a readable format. write_premise((Premise_1, Premise_2)) :- !, write_premise(Premise_1), write_premise(Premise_2). write_premise(not Premise) :- !, write(' '), write(not), write(' '), write(Premise),nl. write_premise(Premise) :- write(' '), write(Premise),nl. % Utility Predicates. %retractall(X) :- retract(X), fail. %retractall(X) :- retract((X:-Y)), fail. %retractall(X). % This is the sample automotive diagnostic knowledge base for use % with the EXSHELL expert system shell in section 12.2 of the text. % When running it, be sure to load it with the file containing % EXSHELL. % To start it, give PROLOG the goal: % solve(improve(X), CF). % Knowledge Base for simple automotive diagnostic expert system. % Top level goal, starts search. rule((improve(Advice) :- (defect(X),improve(X, Advice))), 100). % rules to infer bad component: rule((defect(english) :- (low_score(standard_english_test),not do_you_have_practical_experience_in_communicating_with_english)),90). rule((defect(research_background):- (not do_you_have_papers_published, not do_you_have_working_experience)),90). rule((defect(research_background):- (not do_you_have_scientific_research_experience, not do_you_have_working_experience)),90). rule((defect(gpa_in_undergraduate):- (low_score(what_is_your_average_score_in_all_courses),low_score(what_is_your_average_score_in_major_courses_in_last_two_years))),90). % Rules to infer system that failed. rule((low_score(standard_english_test) :- (low_score(gre), low_score(toefl))),90). rule((low_score(gre) :- (low_score(what_is_your_score_of_verbal_section_in_gre_general_test), low_score(what_is_your_score_of_analytical_writing_section_in_gre_general_test))),90). rule((low_score(what_is_your_score_of_verbal_section_in_gre_general_test) :- what_is_your_score_of_verbal_section_in_gre_general_test),90). rule((low_score(what_is_your_score_of_analytical_writing_section_in_gre_general_test) :- what_is_your_score_of_analytical_writing_section_in_gre_general_test),90). rule((low_score(toefl) :- (low_score(what_is_your_score_of_listening_comprehension_in_toefl), low_score(what_is_your_score_of_grammar_in_toefl),low_score(what_is_your_score_of_reading_comprehension_in_toefl))),90). rule((low_score(what_is_your_score_of_listening_comprehension_in_toefl) :- what_is_your_score_of_listening_comprehension_in_toefl),90). rule((low_score(what_is_your_score_of_reading_comprehension_in_toefl) :- what_is_your_score_of_reading_comprehension_in_toefl),90). rule((low_score(what_is_your_score_of_grammar_in_toefl) :- what_is_your_score_of_grammar_in_toefl),90). rule((low_score(what_is_your_average_score_in_all_courses):- what_is_your_average_score_in_all_courses),90). rule((low_score(what_is_your_average_score_in_major_courses_in_last_two_years):- what_is_your_average_score_in_major_courses_in_last_two_years),90). % Rules to make reccommendation for repairs. rule(improve(english, 'study harder in English'),100). rule(improve(gpa_in_undergraduate, 'try to improve your grade piont average by, say, getting admitted into a local graduate program.'),100). rule(improve(research_background, 'try to gain some relative experience'),100). % askable descriptions askable(what_is_your_score_of_verbal_section_in_gre_general_test). askable(what_is_your_score_of_analytical_writing_section_in_gre_general_test). askable(what_is_your_score_of_listening_comprehension_in_toefl). askable(what_is_your_score_of_reading_comprehension_in_toefl). askable(what_is_your_score_of_grammar_in_toefl). askable(do_you_have_practical_experience_in_communicating_with_english). askable(what_is_your_average_score_in_all_courses). askable(what_is_your_average_score_in_major_courses_in_last_two_years). askable(do_you_have_papers_published). askable(do_you_have_working_experience). askable(do_you_have_scientific_research_experience). askable(do_you_have_working_experience). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%