Problog mpe with annotated disjunctions - problog

I'm writing a problog program over a set of triples showing the location of some objects. The goal is to find the most probable feasible world that satisfy all the non-probabilistic rules. (I'm using problog-MPE).
When I run the following:
0.4::t(a,right,b);0.6::t(a,left,b).
0.4::t(b,right,a);0.6::t(b,left,a).
0.4::t(c,right,a);0.6::t(c,left,a).
t(Y,left,X) :- t(X,right,Y).
t(Y,right,X) :- t(X,left,Y).
query(t(_,_,_)).
I obtain a solution that is not feasible (since right and left predicate are in the annotated disjunction for pairs a,b and b,a).
t(a,right,b)
t(a,left,b)
t(b,right,a)
t(b,left,a)
\+(c,right,a)
(c,left,a)
(a,right,c)
\+(a,left,c)
% Probability: 0.216
How can I write a program in which I force the XOR disjunction?
I would expect/want either one of these 2 solutions:
t(a,right,b)
t(b,left,a)
\+(c,right,a)
(c,left,a)
(a,right,c)
\+(a,left,c)
or
t(a,left,b)
t(b,right,a)
\+(c,right,a)
(c,left,a)
(a,right,c)
\+(a,left,c)
How can I write a program to obtain this?

Related

Prolog: existentially quantifying

I am trying to understand the usage of existentially quantifying. What I know by now is this technique is used with setof, findall, bagof. Further, I found a tutorial. However, I am not sure when and how I do the Vars^Goal (existentially quantifying) in Prolog.
Here is the example, my goal is to find two employees who know each other but work at different companies, binding the result with L showing Name1-Name2:
company('Babbling Books', 500, 10000000).
company('Crafty Crafts', 5, 250000).
company('Hatties Hats', 25, 10000).
employee(mary, 'Babbling Books').
employee(julie, 'Babbling Books').
employee(michelle, 'Hatties Hats').
employee(mary, 'Hatties Hats').
employee(javier, 'Crafty Crafts').
knows(javier, michelle).
My first instinct is to use the query
?-employee(N1,C1),employee(N2,C2),C1\=C2,knows(N1,N2).
The query found the answer but doesn't render it into the correct format. The correct one is:
?-setof(N1-N2, (C1,C2)^(employee(N1,C1),employee(N2,C2),C1\=C2,knows(N1,N2)), L).
How could I understand the (C1,C2)^(employee(N1,C1),employee(N2,C2),C1\=C2,knows(N1,N2)) ? And what's the concept of it? Thanks.
I am not sure when and how I do the Vars^Goal (existentially quantifying) in Prolog.
The easiest answer is: Don't do it, ever. You can always introduce an auxiliary predicate that captures exactly the query you want, exposing exactly the arguments you want and nothing else (that would require quantification), and with a nice self-documenting name.
In your example, you can define:
different_company_acquaintances(N1, N2) :-
employee(N1, C1),
employee(N2, C2),
C1 \= C2,
knows(N1, N2).
and then express your setof query as:
?- setof(N1-N2, different_company_acquaintances(N1, N2), L).
L = [javier-michelle].
This is easier to read because of the predicate name and because it hides the irrelevant implementation details. Note that in the predicate definition the arguments are only the data the caller cares about (the employees), and there are no arguments for the data the caller doesn't care about (the companies).
How could I understand the (C1,C2)^(employee(N1,C1),employee(N2,C2),C1\=C2,knows(N1,N2)) ?
The ^ syntax, whatever the exact correct form is, is meant to signal variables that, if you wrote out a separate predicate definition, would only occur in the predicate's body, not as its arguments. This tells setof and friends that every time it tries to execute the goal (employee(N1,C1),employee(N2,C2),C1\=C2,knows(N1,N2)) it should do so with unbound variables C1 and C2. In other words, it should not try to retain the values of C1 and C2 from one attempt to the next.

Graph implementation (does graph include all vertices?)

Trying to implement following predicate, which takes on input
list of lists - one list = one tested graph T (as edges)
graph G itself (as edges)
and tests whether T includes all of the vertices of G. If it does(true) should return it. Basically it's list filtering.
What I have so far is:
covb([],G).
covb([H|R],G) :-
isItCov(G,H), covb(R,G).
isItCov([],H).
isItCov([V-W|R],H) :-
vertex(V,H),
vertex(W,H),
isItCov(R,H).
vertex(V,[V-_|G]).
vertex(V,[_-V|G]).
vertex(V,[_|G]):- vertex(V,G).
For covb([[a-c,c-b,c-d]],[a-b,a-c,a-d,c-d,b-c]) works fine(true). For covb([[a-c]],[a-b,a-c,a-d,c-d,b-c]) works fine too (false). I got an issue while I call it with multiple lists like covb([[a-c,c-b,c-d],[a-c]],[a-b,a-c,a-d,c-d,b-c]). which should work only for the first one.
I actually got two questions -
Why does it work for one list only?
I want to return items of lists of lists which passed the condition and returned true (that's the filtering part). How should I do that?
First of all, your program has a number of singleton variable warnings. Do not ignore singleton variable warnings. They can hide real bugs. Also, since more experienced Prolog users here know that programs with singleton variable warnings are not even worth running, they will (a) just see the warnings and decide that they are no longer interested in trying to help you, or (b) fix the warnings on their side, but then by definition they will be working on a program that is no longer the program you posted!
Now for your questions.
Why does it work for one list only?
It's really not clear what you are asking here, or just above with "covb([[a-c,c-b,c-d],[a-c]],[a-b,a-c,a-d,c-d,b-c]). which should work only for the first one."
This query does fail:
?- covb([[a-c,c-b,c-d],[a-c]],[a-b,a-c,a-d,c-d,b-c]).
false.
This comes down to testing each of the two lists:
?- isItCov([a-b,a-c,a-d,c-d,b-c], [a-c,c-b,c-d]).
true .
?- isItCov([a-b,a-c,a-d,c-d,b-c], [a-c]).
false.
The first list does cover the graph, while the second doesn't. Overall, your definition of covb/2 is written to succeed if all lists cover the graph. This is not the case, so your covb/2 query fails.
Was this what you wanted to know?
I want to return items of lists of lists which passed the condition and returned true (that's the filtering part). How should I do that?
You could see if your Prolog's documentation has something for the word "filter". On SWI-Prolog you can do this:
?- apropos(filter).
true.
This will point you to the include/3 predicate, which seems to do what you want:
?- include(isItCov([a-b,a-c,a-d,c-d,b-c]), [[a-c,c-b,c-d],[a-c]], Covers).
Covers = [[a-c, c-b, c-d]].
If you want to write a filter predicate for your concrete application, it might look something like this:
graph_covers(_Graph, [], []).
graph_covers(Graph, [Nodes|NodesRest], Covers) :-
( isItCov(Graph, Nodes)
-> Covers = [Nodes|CoversRest]
; Covers = CoversRest ),
graph_covers(Graph, NodesRest, CoversRest).
This is similar to your predicate, it just adds an extra argument to collect those node lists for which isItCov/2 succeeded. If it did not succeed, it continues with a list not containing that current node list.
?- graph_covers([a-b,a-c,a-d,c-d,b-c], [[a-c,c-b,c-d],[a-c]], Covers).
Covers = [[a-c, c-b, c-d]] ;
false.

How to check whether some variable returns something in predicate

Lets assume I have facts as follows:
airport(nyc,'newyork').
I want want to display a message if the user inputs an airport that doesn't exist.
My Attempt:
isAirport(Air) :-
airport(Air,T),
(var(T) -> true
;
write('Airport not found'),
fail
).
However, this doesn't seem to work.
First let's see what happens if you query a conjunction (the , operator) first:
?- airport(nyc, _), write('found!').
found!
true.
?- airport(abc, _), write('found!').
false.
This means, isAirport(abc) directly fails after trying airport(abc,_) without the rest of your predicate being evaluated. In many cases, you can therefore get by without an explicit if-then-else construct and just write something of the form
predicate(X) :-
first_condition(X),
second_condition(X).
and it will only succeed if both conditions are fulfilled for X.
In case you really want to create some user interface, this is a bit more tricky, because I/O is inherently non-logical, in particular when there is backtracking involved. We usually call a program which behaves like we would expect from a logical formula pure and when it contains non-logical constructs like I/O or the cut operator ! are called impure.
Unfortunately, the if-then-else construct (-> and ;) and negation (\+) are implemented via cut and therefore impure as well. Luckily, most of the time people want a conditional, a pure disjunction is sufficient:
case(1,a).
case(2,b).
We have an automatic branching from the execution mechanism of Prolog:
?- case(X,Y).
X = 1,
Y = a ;
X = 2,
Y = b.
But sometimes we really want to do something that needs the impure constructs, like user input. Then the easiest way to keep the nice logical properties of our program is to separate the task into pure and impure ones:
main :-
uinput(Data),
pure_predicate(Data, Result),
write(Result).
After we have done all the impure parts, Data is unified with the user data we wanted. Let's have a look at the implementation of uinput/1:
uinput(data(Airport,D-M-Y)) :-
format('~nAirport? '),
read(Airport),
( ground(Airport), airport(Airport, _) )
->
(
format('~nDay? '),
read(D),
format('~nMonth? '),
read(M),
format('~nYear? '),
read(Y),
( ground(D-M-Y), isDate(D-M-Y) )
->
true
;
throw(failure('unknown date'))
)
;
throw(failure('unknown airport'))
.
We successively read terms from the input and throw an exception if we can't handle it. For the if-then-else construct to work, we need to take special care. If we compare the two queries:
?- between(1,3,X), write(X).
1
X = 1 ;
2
X = 2 ;
3
X = 3.
and
?- between(1,3,X) -> write(X); false.
1
X = 1.
you can see that the if-then-else is losing solutions. This means we need to make sure that our condition is deterministic. Asking for a user input term to be ground is already a good idea, because without variables, there is only one solution term. Still, a call to one of the data-predicates airport/1 and isDate/1 might generate the same term multiple times or not terminate at all. In this particular case, we just need to make sure that each airport has a unique shortcut name, we can also generate dates without repetition:
airport(nyc, 'New York City').
airport(wdc, 'Washington DC').
isDate(X-Y-Z) :-
between(1,31,X),
between(1,12,Y),
between(1970,2100,Z).
Another trick in the implementation of uinput is that we just succeed with true when we have validated everything. The only effect of is now that Data is instantiated with whatever the user entered.
If we give a dummy implementation of the actual implementation, we can already try the implementation oursevles:
pure_predicate(_Data, Result) :-
% here goes the actual stuff
Result='we have found something awesome'.
On the prompt we can use the pure predicate without trouble:
?- pure_predicate(someinputdata,Y).
Y = 'we have computed something awesome'.
On the other hand, we can also use the full predicate as follows:
?- main(_).
Airport? wdc.
Day? |: 1.
Month? |: 2.
Year? |: 2000.
we have found something awesome
true.
Since we are using read, we have to input prolog terms and terminate with a dot ., but everything worked as expected.
In case the user input fails, we get:
?- main(_).
Airport? bla(X).
ERROR: Unhandled exception: failure('unknown airport')
Please note that we only went through this trouble to actually fail early and give a user message in that case. For the actual computation, this is completely unneccessary.
In the code below you are making false assumption that T will remain unbound in case if airport will not be found in database:
airport(Air, T)
What happens actually is that call to airport(Air, T) will make isAirport(Air) to fail immediately and your var(T) and other parts will not be executed at all.
Try this code instead:
isAirport(Air) :-
airport(Air, _T), ! ; write('Airport not found'), fail.

Summing an already outputted list

This is the knowledge base I am working with:
localLib('AHorowitz','Stormbreaker',2).
localLib('AHorowitz','Scorpia',4).
localLib('AHorowitz','Ark Angel',6).
The key for the knowledge base is as follows:
localLib(W,B,C) where
W=Writer
B=Book
C=Acknowledgements
I would like to write a rule that adds up all the acknowledgements of the writer.
This is the code I have written so far:
getAcknowledgement(W,X):- findall(C,localLib(W,_,C),X).
This rule helps me list all the acknowledgements in separate list e.g.
?- getAcknowledgement('AHorowitz',X).
X = [2, 4, 6]
I am now getting stuck on how to add these items. I know of the sum_list built in and though I know it is not correct the thing I want to achieve is this:
getAcknowledgement(W,X):- findall(C,localLib(W,_,C),X).
sum_list(X,[getAcknowledgement]).
/* I would like to sum the output that I receive from the first rule above.
The KB has been simplified in this example to 3 clauses however in reality
there are 1000.*/
How would I go about doing this, any help would be great?
It sounds like you want to find the count of acknowledgements by writer.
bagof/3 is your friend here. It
bagof(+Template, :Goal, -Bag)
Unify Bag with the alternatives of Template. If Goal has free variables besides the one
sharing with Template, bagof/3 will backtrack over the alternatives of these free
variables, unifying Bag with the corresponding alternatives of Template. The construct
+Var^Goal tells bagof/3 not to bind Var in Goal. bagof/3 fails if Goal has no
solutions.
findall/3 is
equivalent to bagof/3 with all free variables bound with the existential operator (^),
except that bagof/3 fails when Goal has no solutions.
So...this should get you the summed count of knowledgements for a given writer, or, if Writer is unbound, on backtracking, it will find the solutions for all writers, one at a time.
acknowledgements_by_writer( Writer , Acknowledgements ) :-
bagof( N , local_lib(Writer,_,N) , Ns ) ,
sum_list(Ns,Acknowledgments).
If you want the overall count of acknowledgements, something like this ought to do you
total_acknowledgements(T) :-
findall(N,local_lib(,,N),Ns),
sum_list(Ns,T).

Understanding a prolog predicate

I'm having some troubles in understanding the following prolog predicate ,
I can understand that it concatenate some chars , also produces the possible lists (first & second goal ) , but I can't understand how it do this ? how it executes ?
domains
i=integer
l=i*
slist=string*
clist=char*
predicates
nondeterm conc(clist,clist,clist).
clauses
conc([],L,L).
conc([H|L1],L2,[H|L3]):-
conc(L1,L2,L3).
The first goal
goal
conc(['a','b'],['c','d'],L).
result
L=['a','b','c','d']
the second goal
goal
conc(L1,L2,['a','b','c']).
result
L1=[], L2=['a','b','c']
L1=['a'], L2=['b','c']
L1=['a','b'], L2=['c']
L1=['a','b','c'], L2=[]
4 Solutions
I'm neither an expert in prolog, nor in logic, but I'll try to explain what I think how it works.
After the call to:
<- conc(['a','b'],['c','d'],L).
Prolog will look for a predicate that matches the signature. In this case that would be:
conc([H|L1],L2,[H|L3])
It tries to resolve the variables with the given data.
|1: H:=['a'], L1:=['b'], L2:=['c','d']
Now it steps into the recursion with these data calling:
<- conc(['b'], ['c','d'], L3).
|2: H:=['b'], L1:=[], L2:=['c','d']
<- conc([], ['c','d'], L3).
The last line causes prolog to use the predicate with the signature:
conc([],L,L).
resolving:
|3: L:=['c','d']
Now Prolog is able to construct the concatinated List handing over L up the recursion stack.
|2: [H|L3]:=['b','c','d']
|1: [H|L3]:=['a','b','c','d']
I hope that is a hint in the right direction. Maybe you should read this article for clarification

Resources