Prolog - Count all patient's symptoms

2019-07-21 05:36发布

I'm trying to count all patient's symptoms to calculate the certainty factor for the disease, but I'm just getting one symptom of each disease.
Also the result shows some duplicates.
The certainty factor is the number of patient's symptoms/the total of symptoms of the disease:

start:- 
  write('Enter the name of the patient: '), read(Patient),
  write('Enter the symptoms: '), read(Symptoms), write('\n'),
  countSint(Diseases, Symptoms , Patient).

countSint(Diseases, Symptoms , Patient) :-
  findall(Sint , member(Sint, Symptoms),   L1), length(L1 , Size),
  (  Size < 2
  -> writeln('Enter with at least 3 symptoms...\n'), start
  ;  Size > 1
  -> write('\n Enter semicolon...:\n\n'), write('Patient: '), write(Patient),
     diagnose(Symptoms,Diseases, L)
  ).

diagnose(Symptoms,Diseases,L) :- search(Symptoms, Diseases, L).

% disease(Disease, Symptoms, Num).
disease(meningitis,[fever, stiff_neck],2).
disease(dengue,[fever, vomiting, red_spots], 3).

% search(Symptoms, Diseases, L).
search([H|T] , Diseases, L) :-
  disease(Disease, Symptoms, Num),
  Disease0 = [Disease,Diseases],
  member(H, Symptoms),
  search(T , Diseases0, L),
  write('has '), write(Disease), writeln(': '),
  setof(H, (disease(Disease, Symptoms, Num),
            member(H, Symptoms)), L),
  length(L, Size),
  calc_cf(Num, Size, R).

calc_cf(Num, Size, R):- % Calculate the certainty factor
  R is Size / Num * 100,
  write('The certainty factor is '),
  write(R),
  writeln('%').

Can anyone help me, please?

1条回答
The star\"
2楼-- · 2019-07-21 06:22

this seems useless:

findall(Sint , member(Sint, Symptoms),   L1)

simply rewrite Symptoms as L1. Why?

In this snippet

  (  Size < 2
  -> writeln('Enter with at least 3 symptoms...\n'), start
  ;  Size > 1
  -> write('\n Enter semicolon...:\n\n'), write('Patient: '), write(Patient),
     diagnose(Symptoms,Diseases, L)
  )

there should be another alternative.

This fact disease(Disease, Symptoms, Num). should be useless, but it will introduce unbound variables that make more difficult any further processing.

You could consider to take a look to library(aggregate), where you find well crafted predicates for counting solutions, something like

countSint(Diseases, Symptoms, Patient) :-
  aggregate(count, diagnose(Symptoms, Diseases, _), Count),
  format('diagnosed:~d for:~w~n', [Count, Patient]).

edit

It's better to separate logic from presentation, and to get some good feedback here on SO I think you should remove write/read from code, and show instead some example you care about. Now I show the essential formula you need, as I can guess from your comment:

disease(meningitis, [fever, stiff_neck]).
disease(dengue, [fever, vomiting, red_spots]).

% find diseases from symptoms, sort by certainty factor
diagnose(Symptoms, Diseases) :-
     setof(CF-Disease, common_symptoms(Symptoms, Disease, CF), Diseases).

common_symptoms(Symptoms_Patient, Disease, CF) :-
    disease(Disease, Symptoms_Disease),
    intersection(Symptoms_Patient, Symptoms_Disease, Common_Symptoms),
    length(Common_Symptoms, NCS),
    length(Symptoms_Disease, NSD),
    CF is NCS / NSD * 100.

test:

?- diagnose([fever, stiff_neck],L).
L = [33.33333333333333-dengue, 100-meningitis].
查看更多
登录 后发表回答