How to set mutually exclusive probabilities in Problog? - prolog

A person X can either be inpatient or outpatient.
Given the fact location(X,outpatient) how can Problog infer that the probability of location(X,inpatient) is 0?
For example I want a side effect of:
person(1).
location(1,inpatient).
dependent(1,opioids).
receive(1,clonidine).
query(detoxification(1,opioids,success)).
to be an inference that location(1,outpatient) has zero probability.
If I write location(X,outpatient);location(X,inpatient)., all queries return both with a probability of 1.
If I write P::location(X,outpatient);(1-P)::location(X,inpatient). that gives an error because I haven't specified a value for P. If I specify a value for P, that value is never updated (as expected because Prolog treats variables as algebraic variables and I haven't told Problog to update P.
If I write location(X,outpatient) :- \+ location(X,inpatient). I create a negative cycle, which I have to if I am to specify the inverse goal.

One solution:
P::property(X,location,inpatient);(1-P)::property(X,location, outpatient) :-
inpatient(X),
P is 1.
P::property(X,location,outpatient);(1-P)::property(X,location, inpatient) :-
outpatient(X),
P is 1.
P::inpatient(X);(1-P)::outpatient(X) :-
property(X,location,inpatient),
P is 1.
P::outpatient(X);(1-P)::inpatient(X) :-
property(X,location,outpatient),
P is 1.
This binds inpatient/1 to property/3 for the property of location with value inpatient.

Related

Planning with Numerical Values and PROLOG

I am trying to use this Planner https://www.cs.unm.edu/~luger/ai-final/code/PROLOG.planner.html .
I want to search a space with a numerical value. Below you can see my implementation of sum that is tested and seems to work. Then there are my two moves, plus and minus, where I delete the value(X) and add value(Y) where Y is X +- 1 respectively.
If I now consult the planner (last statement with go), I do not get the expected result of plus() but instead false as the planner does not find a way from value(2) to value(3).
sum(X,Y,Z) :- Z is X+Y.
move(plus(), [value(X)], [del(value(X)), sum(X,1,Y) , add(value(Y))]).
move(minus(), [value(X)], [del(value(X)), sum(X,-1,Y) , add(value(Y))]).
go([value(2)], [value(3)]).
The predicate move(Action, Preconditions, Effects) describes the changes caused by the execution of Action in a state where the conditions established in list Preconditions hold. In a fact for this predicate, the list Effects must consist only of terms of the form add(Fluent) and del(Fluent). So, I think the correct definition of actions plus and minus should be as follows:
move(plus, [value(X)], [del(value(X)), add(value(Y))]) :- Y is X + 1.
move(minus, [value(X)], [del(value(X)), add(value(Y))]) :- Y is X - 1.

Prolog: Chaining multiple rules

So I am an absolute beginner in Prolog. I am learning recursion at the moment and this is what I got until now on my task.
dance(start).
dance(forward(T)) :- dance(T).
dance(backward(T)) :- dance(T).
count(start,0,0).
count(forward(X),succ(Y),Z) :- count(X,Y,Z).
count(backward(X),Y,succ(Z)) :- count(X,Y,Z).
greater(succ(0),0).
greater(succ(Y),succ(Z)):-greater(Y,Z).`
Summary of what this is supposed to do: There can be dances starting with the "start" and then either forward or backward addition per recursion. In count, I managed to be able to count the amount of forward and backward in a given sequence and save them in the "succ" notation and in greater I want to compare two of such "succ" numbers. And greater shall be true if the first argument is larger (consists of more "succs" than the second argument.
Now my task is to write a new rule "more(X)" which is true if the sequence X (build from dance) has more forward than backward in it. I think I have all the subtasks I need for it but now I am helpless with chaining them together because until now I only had 2 rules with the same amount of parameters but in this case, I got one with one, two, and three parameters. The solution should be something like this
more(X):-greater(Y,Z)
but how do I get my "succ" umbers from "count" to "greater" and the given sequence X to "count"? I do have to change some of the rules otherwise count is never called, right?
So it should be more like more(X):-greater(count(X,Y,Z)) ?
But like this, I would have to change the greater rules to be able to "get" this type of parameter.
Example query ?- more(backward(forward(start))).
false.
?- more(forward(start)).
true.
Your dance/1 and count/3 predicates seems correct.
If you want "greater" where greater(X, Y) means that X is greater than Y, you'd write:
greater(succ(_), 0).
greater(succ(X), succ(Y)) :- greater(X, Y).
Your solution checks if X is exactly one greater than Y.
Note that nothing is greater than 0.
If you implement more/1 in terms of count/3 and greater/2, you'd write:
more(X) :-
count(X, Forward, Backward),
greater(Forward, Backward).
So it should be more like more(X):-greater(count(X,Y,Z)) ?
No, you are writing that as if it is Python and greater(count(X,Y,Z)) will call greater(...) on the return from count. Prolog predicates are not function calls, and count(...) does not return anything in that way.
The result of the count is Y and Z. (These names you are using could be clearer). Do the count, and then after, use the Y and Z for something else.
count(X,Y,Z),
greater(Y,Z)
The comma being AND; "this code works if count of X is Y and Z AND Y is greater than Z".

decrement the same variable in Prolog

Something like this:
decr(X, X) :-
X is X-1.
I want to use it for decrement a number in the parent rule , if this number equal 0 for example, the parent rule return false.
Prolog is declarative: one of the properties of a declarative language is that once you set a variable, you cannot give it another value anymore. In Prolog backtracking can of course "unground" a variable and furthermore you can assign a partially grounded expression to a variable (like X=f(1,_)), but when you move deeper into the call stack, each expression can only be grounded further.
As a result: you have to use another variable. Like:
decr(X,NX) :-
NX is X-1.
This is also logical: here you defined decr(X,X) and since the argument of predicates in Prolog have no input/output direction, it is unclear whether you want to call it like decr(4,3), decr(X,3), decr(4,X) or decr(X,Y). So how can Prolog "know" that your second X is supposed to be the "new X"? It is thus a "fundamental property" of Prolog you cannot use X, call a predicate, and all of a sudden X has a different value (it can however - as said before - be grounded further, but an integer cannot be grounded further).
The reason why it will always error or fail is because, either X is not instantiated: (like decr(_,_)) in which case Prolog cannot calculate X is _-1, or you have given one of the argument a number (decr(X,3), decr(4,X) or decr(3,3)), but in that case you ask that both operands can unify (since they are both X) and are off by one at the same time, which is a contradiction.
As already mentioned, you can't reassign variables in Prolog, but the closest thing available out-of-box to what you apparently want is succ/2 predicate:
?- succ(1, X).
X = 2.
?- succ(X, 5).
X = 4.
The next closest is probably plus/3:
?- plus(1, 2, X).
X = 3.
?- plus(1, X, 3).
X = 2.
?- plus(X, 2, 3).
X = 1.

CLP Prolog - Logic Programming

we have a list of list think an example ?- solve([[40,A,B],[30,B],[60,A,B,C]]),label([A,B,C]). will succeed with replacing B=30,A=10 and C=20.
The constraint with this example is A+B=40, A+B+C=60 and generally every variable are in between 0 and 100. Every list must begin with a constant and it includes at least one variable.
:- use_module(library(clpfd)).
sum([],0). % if the list is empty.
sum([X|XS],Z) :-
sum(XS,Z1),
X in 0..100,
Z #= X+Z1.
solveOne([Const|Var]) :-
sum(Var,Const).
solve([]). % if the list of list is also empty
solve([First|Others]) :-
solveOne(First),
solve(Others).
I am a bit skeptic the idea of base case,facts. Because every list must include at list one variable according to constraints, on the other hand we think about the "empty list" situation.?
First, the obvious problem: you define both a solve/2 and a solve/1 predicate (solve([],0)). The ",0" is probably unwanted.
Apart from that, if you have only a constant, like [X], then solveOne succeeds only if X is zero; otherwise, it fails according to sum([],0). So, in a sense, you indirectly check that you can have at least one variable if you assume your sum is always strictly positive.
In order to explicitely check that there is effectively at least one variable, then you can modify solveOne as follows:
solveOne([Const,V1|Vars]) :-
sum([V1|Vars], Const).
#coredump answer should put you on right track. If you are interested in writing lean code, consider this more succint definition (tested in SWI-Prolog)
solve(L) :- maplist(solveOne, L).
solveOne([C|Vs]) :- Vs ins 0..100, sum(Vs, #=, C).
?- solve([[40,A,B],[30,B],[60,A,B,C]]).
A = 10,
B = 30,
C = 20.

Sum of a list in prolog

I'm reading 'the art of prolog' book and I found an exercise that reads 'Define the relation sum(ListOfIntegers,Sum) which holds if Sum is the sum of the ListOfIntegers, without using any auxiliary predicate' .I came up with this solution:
sum([],Sum).
sum([0|Xs], Sum):-sum(Xs, Sum).
sum([s(X)|Xs], Sum):-sum([X|Xs],s(Sum)).
Which does not work exactly as I would want it to.
?- sum([s(s(0)),s(0),s(s(s(0)))],X).
true ;
false.
I was expecting X to be
s(s(s(s(s(s(0))))))
I thought that the problem is that I have to 'initialize' Sum to 0 in the first 'iteration' but that would be very procedural and unfortunately I'm not quite apt in prolog to make that work.
Any ideas or suggestions?
Your first clause should read
sum([], 0).
With that change, the vacuous true return goes away and you're left with one problem: the third clause reverses the logic of summation. It should be
sum([s(X)|Xs], s(Sum)) :- sum([X|Xs], Sum).
because the number of s/1 terms in the left argument to sum/2 should be equal to the number of them in the right argument.
The best way to localize the problem is to first simplify your query:
?- sum([0],S).
true.
?- sum([],S).
true.
Even for those, you get as an answer that any S will do. Like
?- sum([],s(s(0))).
true.
Since [] can only be handled by your fact, an error must lie in that very fact.
You stated:
sum([], Sum).
Which means that the sum of [] is just anything. You probably meant 0.
Another error hides in the last rule... After fixing the first error, we get
?- sum([0],Sum).
Sum = 0.
?- sum([s(0)],Sum).
false.
Here, the last clause is responsible. It reads:
sum([s(X)|Xs], Sum):-sum([X|Xs],s(Sum)).
Recursive rules are relatively tricky to read in Prolog. The simplest way to understand them is to look at the :- and realize that this should be an arrow ← (thus a right-to-left arrow) meaning:
provided, that the goals on the right-hand side are truewe conclude what is found on the left-hand side
So, compared to informal writing, the arrows points into the opposite direction!
For our query, we can consider the following instantiation substituting Xs with [] and X with 0.
sum([s(0)| [] ], Sum) :- sum([0| []],s(Sum)).
So this rule now reads right-to-left: Provided, sum([0],s(Sum)) is true, ... However, we do know that only sum([0],0) holds, but not that goal. Therefore, this rule never applies! What you intended was rather the opposite:
sum([s(X)|Xs], s(Sum)):-sum([X|Xs],Sum).
I'm not really following your logic, what with all the seemingle extraneous s(X) structures floating about.
Wouldn't it be easier and simpler to do something like this?
First, define your solution in plain english, thus:
The sum of an empty list is 0.
The sum of a non-empty list is obtained by adding the head of the list to the sum of the tail of the list.
From that definition, the prolog follows directly:
sum( [] , 0 ) . % the sum of an empty list is 0.
sum( [X|Xs] , T ) :- % the sum of an non-empty list is obtained by:
sum( Xs , T1 ) , % - first computing the sum of the tail
T is X + T1 % - and then, adding that the to head of the list
. % Easy!

Resources