Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to apply the universal quantifier in Prolog?

Tags:

prolog

Suppose you have a disease diagnosis Prolog program that starts with many relations between diseases and symptons:

causes_of(symptom1, Disease) :-
    Disease = disease1;
    Disease = disease2.
causes_of(symptom2, Disease) :-
    Disease = disease2;
    Disease = disease3.
causes_of(symptom3, Disease) :-
    Disease = disease4.

has_symptom(person1, symptom1).
has_symptom(person1, symptom2).

How can I create a rule with the head 'has_disease(Person, Disease)' that will return true if the person has all the symptoms from that disease? Using the example above the following would a sample output:

has_disease(person1, Disease).
   Disease = disease2.
like image 879
Thiago Padilha Avatar asked Jul 05 '11 13:07

Thiago Padilha


2 Answers

Well, there is probably a much simpler way to do this, as my Prolog skills are minor at best.

has_disease(Person, Disease) :- atom(Disease),
    findall(Symptom, has_symptom(Person, Symptom), PersonSymptoms),
    findall(DSymptom, causes_of(DSymptom, Disease), DiseaseSymptoms),
    subset(DiseaseSymptoms, PersonSymptoms).

has_diseases(Person, Diseases) :-
    findall(Disease, (causes_of(_, Disease), has_disease(Person, Disease)), DiseaseList),
    setof(Disease, member(Disease, DiseaseList), Diseases).

To be called as follows:

?- has_diseases(person1, D).
D = [disease1, disease2, disease3].

The findall/3 predicate is used first to find all symptoms a person has, then again to find all symptoms a disease has, then a quick check to see if the disease's symptoms are a subset of the person's.

The way I have written the has_disease/2 predicate prevents it from giving a list of diseases. So I created has_diseases/2, which performs another findall on any disease it can find, using has_disease/2 as the check. A setof/3 call is used last to get unique results on the disease list and order it for convenience.

NB. The atom/1 on the has_disease/2 primitive is just to ensure a variable is not passed in for Disease, as it does not work in that case, at least not for me.

like image 150
Orbling Avatar answered Sep 20 '22 19:09

Orbling


You will need a way to query all symptoms, e.g. with findall(S,cause_of(S,disease),SS), where SS will be the list of symptoms for this disease.

like image 33
Volker Stolz Avatar answered Sep 24 '22 19:09

Volker Stolz