How do you save all possible solutions in SWI-Prolog? - prolog

I have this predicate that has about a thousand possibilities and I need all possibilities as an output. It is not possible to simply copy and paste all listed possibilities in SWI-Prolog on Windows since you can only scroll up so much.
My predicate looks like this:
?- question(X,Y,Z).
X = 'Fo',
Y = 'Ob',
Z = 'Ar' ;
X = 'Fo2',
etc...
I was wondering if there was a way to save the result in a file or something?

Use findall/3:
findall([X,Y,Z],question(X,Y,Z),R).
R shall be bound to the list of all [X,Y,Z] such that question(X,Y,Z) succeeds.
For more information see: Documentatin on Findall

You can use something like this:
main :-
tell('output.txt'),
(
question(X,Y,Z),
writeln([X, Y, Z]),
fail
;
told
).
Or you can run the query ( question(X,Y,Z), writeln([X, Y, Z]), fail ; true ). in Prolog and get all solutions at standard output (screen).

SWI-Prolog offers a way to save the interaction carried on the REPL (Read,Eval,Print,Loop) console: see the protocol builtins. This way variables names are retained. Beware, the output could be difficult to process, and long variables will be replaced by ellipsis (you can change this, see these answers).
Otherwise, forall/2 could be a viable alternative
?- open('a.txt',write,S), forall(member(X,[martin,carlo]), format(S,'~q~n',[X])), close(S).

Related

Want PROLOG to require == matches on already matched variables, = for others

I have this code:
contradicts(at(X,_),location(X)).
mustContradict(A, B) :- contradicts(A, B).
contradicts/2 is meant to say: if X is at somewhere, then X can't itself be a location.
mustContradict/2 is meant to say: succeed if A and B are contradictory.
When I run it to detect that if you're at a location, you can't be a location (mustContradict(at(Thing,Location),location(Thing)).) -- it succeeds, as it should. On this one, however:
mustContradict(at(Thing,Location),location(Location)).
it also succeeds, with variable assignment Thing=Location.
I could probably mangle a way to make it ensure all variables are identical when trying to match, something like:
A=at(Thing,Location),B=location(Location),
contradicts(A,AsContradiction),
B==AsContradiction.
but then it would fail on the first test, trying to verify that a Thing that is "at" something can't be a location.
What I think I want is to be able to distinguish variables that are already assigned to other variables from those that are so far not matched to anything.
You shouldn't check your predicates with variables (starting with uppercase), but with terms (starting with lowercase).
mustContradict(at(thing,location),location(location)). fails as it should since thing doesn't equal location. In your example you use variables that can be assigned anything.
I have no idea why you are reassigning mustContradict(A, B) :- contradicts(A, B).
you can change contradicts definition to contradicts(at(X,Y),location(X)) :- not(X == Y).
I wonder if this is not what you wanted to achieve:
at(thing, location).
at(thingLocation, location).
location(location).
location(thingLocation).
contradicts(X) :- at(X,_), location(X).
now contradicts(X). succeeds with X = thingLocation
Looks like the solution was to convert all variables to atoms. Only converting those that were shared or repeated meant that the others could bind to inappropriate things (as in the first example), so the behavior didn't change.
Binding them to atoms, as in this code:
contradicts(at(X,_),location(X)).
mustContradict(X,Y) :-
replaceVariablesWithAtoms(X,NewX), replaceVariablesWithAtoms(Y,NewY),
contradicts(NewX,NewY).
replaceVariablesWithAtoms(Term,NewTerm) :-
Term =.. TermAsList,
terms_to_atoms(TermAsList,NewTermAsList),
NewTerm =..NewTermAsList.
terms_to_atoms([],[]).
terms_to_atoms([H|T],[NewH|NewT]) :-
terms_to_atoms(T,NewT),
term_to_atom(H,NewH).
gives the right answer to both queries.
?- mustContradict(at(Thing,Location),location(Thing)).
true.
?- mustContradict(at(Thing,Location),location(Location)).
false.
Wouldn't it be easier just to write it as you have defined the problem statement:
I have this code:
contradicts(at(X,_),location(X)).
mustContradict(A, B) :- contradicts(A, B).
contradicts/2 is meant to say: "if X is at somewhere, then X can't itself be a location."
mustContradict/2 is meant to say: "succeed if A and B are contradictory."
Assuming that your at/2 and location/1 are facts/predicates in your prolog program . . . why not something like this:
contradiction(X) :- at(X,_), location(X) .

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.

Variable not printing the entire value Prolog

If I assign something like
process([[baby],[boy],[[is]dancing],[with],[[the][family]]],A),
then it gives output as
A = [[baby],[boy],[[is]dancing],[with],[[..][..]]].
I want it to show all the values on terminal.
Something like
A = [[baby],[boy],[[is]dancing],[with],[[the][family]]].
The problem is that the toplevel is truncating the list when they are shown.
You can configure the depth of the maximum nesting with the prolog flag toplevel_print_option, with option max_depth(0), with 0 meaning to show everything.
The helper procedure will modify the prolog flag to change only max_depth to 0, leaving the other options unchanged:
set_toplevel_flags:-
current_prolog_flag(toplevel_print_options, Opts),
(select(max_depth(_), Opts, TOpts) -> NOpts=TOpts ; NOpts=Opts),
set_prolog_flag(toplevel_print_options, [max_depth(0)|NOpts]).
Use the current_prolog_flag/2 predicate with the toplevel_print_options flag. Something like this:
?- current_prolog_flag(toplevel_print_options, X).
X = [quoted(true), portray(true), max_depth(10), spacing(next_argument)].
You can modify the max_depth option value, or alternatively you can type w after getting the abbreviated answer, and prolog will print the answer fully. Pressing p will restore the original format. To make the Prolog wait wor your input after printing the answer, you might want to add some non-determinism to the query by appending ; true. to it. For more information see here.

Prolog Relational Tracking without Lists

I am trying to get a predicate to relate from 1 fact to another fact and to keep going until a specified stopping point.
For example,
let's say I am doing a logistics record where I want to know who got a package from who, and where did they get it from until the end.
Prolog Code
mailRoom(m).
gotFrom(annie,brock).
gotFrom(brock,cara).
gotFrom(cara,daniel).
gotFrom(daniel,m).
gotFrom(X,Y) :- gotFrom(Y,_).
So what I am trying to do with the predicate gotFrom is for it to recursively go down the list from what ever point you start (ex: gotFrom(brock,Who)) and get to the end which is specified by m, which is the mail room.
Unfortunately when I run this predicate, it reads out,
Who = annie.
Who = brock.
Who = cara.
etc.etc....
I tried stepping through the whole thing but Im not sure where it goes from brock to annie, to cara and all the way down till it cycles through trues for infinity. I have a feeling that it has something to do with the wildcard in the function (_), but Im not sure how else I could express that part of the function in order for the predicate to search for the next fact in the program instead of skipping to the end.
I tried using a backcut (!) in my program but it gives me the same error.
Any help is greatly appreciated. I don't want code I just want to know what I am doing wrong so I can learn how to do it right.
Thanks.
I'm afraid this rule is meaningless:
gotFrom(X,Y) :- gotFrom(Y,_).
There is nothing here to constrain X or Y to any particular values. Also, the presence of singleton variable X and the anonymous variable _ means that basically anything will work. Try it:
?- gotFrom([1,2,3], dogbert).
true ;
true ;
What I think you're trying to establish here is some kind of transitive property. In that case, what you want is probably more like this:
gotFrom(X,Z) :- gotFrom(X, Y), gotFrom(Y, Z).
This produces an interesting result:
?- gotFrom(brock, Who).
Who = cara ;
Who = daniel ;
Who = m ;
ERROR: Out of local stack
The reason for the problem may not be immediately obvious. It's that there is unchecked recursion happening twice in that rule. We recursively unify gotFrom/2 and then we recursively unify it again. It would be better to break this into two predicates so that one of them can be used non-recursively.
got_directly_from(annie,brock).
got_directly_from(brock,cara).
got_directly_from(cara,daniel).
got_directly_from(daniel,m).
gotFrom(X,Y) :- got_directly_from(X, Y).
gotFrom(X,Z) :- got_directly_from(X, Y), gotFrom(Y, Z).
This gives us the desired behavior:
?- gotFrom(brock, Who).
Who = cara ;
Who = daniel ;
Who = m ;
false.
Notice this one is resilient to my attack of meaningless data:
?- gotFrom([1,2,3], dogbert).
false.
Some general advice:
Never ignore singleton variable warnings. They are almost always a bug.
Never introduce a cut when you don't understand what's going on. The cut should be used only where you understand the behavior first and you understand how the cut will affect it. Ideally, you should try to restrict yourself to green cuts—cuts that only affect performance and have no observable effects. If you don't understand what Prolog is up to, adding a red cut is just going to make your problems more complex.

How to do this in one function

I was wondering how to do the answer (or first function) to this question in Prolog only using one predicate? The link I'm referring to is here.
Here's an example of what I mean by only calling one predicate:
reverse([X|Y],Z,W) :- reverse(Y,[X|Z],W).
reverse([],X,X).
What are you trying to do and why do you want just one clause for the predicate?
personally I believe that having the ability to write many clauses is one of the great things of prolog and the code is more elegant and readable that way
Anyway, you will probably want to use or. assuming that you have the following clauses:
foo(Arg11,Arg12,Arg13):-
(Body1).
foo(Arg21,Arg22,Arg23):-
(Body2).
foo(Arg31,Arg32,Arg33):-
(Body3).
you should first make sure that every clause has the same arguments (bye bye pattern matching there!):
foo(Arg1,Arg2,Arg3):-
(Body1b).
foo(Arg1,Arg2,Arg3):-
(Body2b).
foo(Arg1,Arg2,Arg3):-
(Body3b).
and then you will use or (;):
foo(Arg1,Arg2,Arg3):-
(Body1b)
; (Body2b)
; (Body3b).
for example,
reverse([X|Y],Z,W):-
reverse(Y,[X|Z],W).
reverse([],X,X).
will become:
reverse(X,Y,Z):-
X = [H|T],
reverse(T,[H|Y],X).
reverse(X,Y,Z):-
X = [],
Z = Y.
and then:
reverse(X,Y,Z):-
(X = [H|T],
reverse(T,[H|Y],X) )
; (X = [],
Z = Y). *%ew ew ugly!*
regarding the example on your first post, there are two different predicates, each having just one clause. the second predicate has 2 arguments while the first one has 1 therefore they are different. The only way to "merge" them would be by simply calling the second one as has_equal_sums(List, _) in the place of the first.
To be honest, I dont see the point of doing this; I doubt you will not get any significant speedup and the code becomes way messier.
Of course, it's your code and there can be restrictions we dont know (that's why I asked what you want to accomplish)

Resources