Finding out which rule fired in a prolog file - prolog

I have a prolog file that classifies a given predicate bongard(A, X) with given background facts.
Snippet of the rules:
bongard(A,[neg]) :- triangle(A,C), \+ in(A,C,D), !.
bongard(A,[neg]) :- \+ triangle(A,C), !.
...
I am executing this program like so: swipl -s file.pl -g "bongard(a, X), write(X)", to obtain the classification for this predicate.
Now I would also like to know which rule triggered and actually bounded the variable. Is there any neat way to do this? Right now I need to keep an additional n files for an original prolog file with n rules. File1 has the first rule, file2 has the first 2 rules.. You get the idea. This way if File2 classifies the rule, I know the second rule fired.
Does anyone have any better suggestions for this?
EDIT: What about giving the predicate a unique number "bongard(A, X, nr)" I could then both write(X) and write(Nr) so I know which predicate fired?

Can you not just add an id number:
bongard(1,A,[neg]) :- triangle(A,C), \+ in(A,C,D), !.
bongard(2,A,[neg]) :- \+ triangle(A,C), !.
...
and then do (eg)
swipl -s file.pl -g "bongard(N,a,X), format('~w (rule ~w)~n',X,N)"

Related

Use expand_term/2 with file for dcg translation

I'm trying to "translate" a file that contains dcg's. in particular i am trying to transform all dcg into normal definite clauses using expand_term/2, however i would like to avoid manually translating all dcgs, so i would try to translate all clauses of the file at once (e.g. passing the whole file) . is there any way to do it?
for example, suppose we have a temp.pl file which contains some dcg:
a(X,Y) --> b(X), c(Y).
d([A | Ax]) --> b(A).
....
....
instead of using expand_term/2 individually for each term, like:
?- expand_term((a(X,Y) --> b(X), c(Y)), Clause).
Clause = [(:-non_terminal(user:a/4)), (a(X, Y, _A, _B):-b(X, _A, _C), c(Y, _C, _B))].
And then replace the dcg with definite clause in file.
I would like to pass for example the whole file (to a clause for example
) which contains the dcg, and translate all the dcg at once and print in a file or as an output, I don't know.
If I understand your question correctly then you are missing the obvious which is that what you seek is already in the SWI-Prolog code. The translation is done as the module is loaded. If you use listing/1 on a DCG predicate the code will list as normal Prolog and not DCGs.
See
dcg.pl
load.pl
expand.pl
apply_macros.pl
Demonstration of listing/1 with DCG
Directory: C:/Users/Groot
File: example.pl (Based on this SO answer )
:- module(example,
[
monlangage/2
]).
:- set_prolog_flag(double_quotes, chars).
monlangage --> "ab" | "a", monlangage.
Example run
Welcome to SWI-Prolog (threaded, 64 bits, version 8.5.3)
...
?- working_directory(_,'C:/Users/Groot').
true.
?- [example].
true.
?- listing(example:_).
monlangage(A, B) :-
( A=[a, b|B]
; A=[a|C],
monlangage(C, B)
).
true.
Notice that the source code is DCG with --> and the listing is not DCG with :-. Also notice that the rewritten clause has two extra arguments.

Outputting prolog in Mac

I have a problem using prolog on a Mac, I figured out how to run it using SWI-Prolog but when I run it, it gives an error and does not give the expected output
Expected output: homer, bart
male(homer).
male(bart).
female(marge).
female(lisa).
female(maggie).
parent(homer, bart).
parent(homer, lisa).
parent(homer, maggie).
parent(marge, bart).
parent(marge, lisa).
parent(marge, maggie).
mother(X, Y) :- parent(X, Y), female(X).
father(X, Y) :- parent(X, Y), male(X).
son(X, Y) :- parent(Y, X), male(X).
daughter(X, Y) :- parent(Y, X), female(X).
?- male(X).
Here is the error I was speaking about earlier
Warning: /Users/[username]/Desktop/simpsons.pl:19:
Warning: Singleton variables: [X]
true.
And instead of outputting homer, bart it outputs true
When programming in Prolog, you put definitions and queries in different places. Definitions go into source files. Queries do not go into source files. You enter them while interacting with the Prolog system in something called the "toplevel" or "prompt" or "shell" or maybe "REPL" (read-eval-print loop).
For example, these are definitions:
male(homer).
male(bart).
female(marge).
female(lisa).
female(maggie).
You have put them in a source file called simpsons.pl. This is correct.
This is not a definition but a query:
?- male(X).
This does not go in a source file. Do not put it in simpsons.pl. Rather, you:
start your Prolog system
load the simpsons.pl file somehow
enter the query male(X). and observe answers
This video: https://www.youtube.com/watch?v=t6L7O7KiE-Q shows these steps with SWI-Prolog on a Mac.
If you are comfortable using a command line, you might also be able to do this simpler. For example, on my (Linux) machine, I can start SWI-Prolog with a command line argument naming a file to be loaded:
$ swipl simpsons.pl
Welcome to SWI-Prolog (threaded, 64 bits, version 7.6.4)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.
For online help and background, visit http://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).
?-
See that ?-? That is the prompt meaning that the toplevel is now waiting for your input. Here is where you enter your male(X) query. You can use ; or Space to cycle through the various answers:
?- male(X).
X = homer ;
X = bart.

How to run prolog queries from within the prolog file in swi-prolog?

If I have a prolog file defining the rules, and open it in a prolog terminal in windows, it loads the facts. However, then it shows the ?- prompt for me to manually type something. How can I add code to the file, so that it will actually evaluate those specific statements as if I typed them in?
something like this
dog.pl
dog(john).
dog(ben).
% execute this and output this right away when I open it in the console
dog(X).
Does anyone know how to do this?
Thanks
There is an ISO directive on this purpose (and more): initialization
If you have a file, say dog.pl in a folder, with this content
dog(john).
dog(ben).
:- initialization forall(dog(X), writeln(X)).
when you consult the file you get
?- [dog].
john
ben
true.
Note that just asserting dog(X). doesn't call dog(X) as a query, but rather attempts to assert is as a fact or rule, which it will do and warn about a singleton variable.
Here's a way to cause the execution the way you're describing (this works for SWI Prolog, but not GNU Prolog):
foo.pl contents:
dog(john).
dog(ben).
% execute this and output this right away when I open it in the console
% This will write each successful query for dog(X)
:- forall(dog(X), (write(X), nl)).
What this does is write out the result of the dog(X) query, and then force a backtrack, via the false call, back to dog(X) which will find the next solution. This continues until there are no more dog(X) solutions which ultimately fails. The ; true ensures that true is called when dog(X) finally fails so that the entire expression succeeds after writing out all of the successful queries to dog(X).
?- [foo].
john
ben
true.
You could also encapsulate it in a predicate:
start_up :-
forall(dog(X), (write(X), nl)).
% execute this and output this right away when I open it in the console
:- start_up.
If you want to run the query and then exit, you can remove the :- start_up. from the file and run it from the command line:
$ swipl -l foo.pl -t start_up
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.2.3)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.
For help, use ?- help(Topic). or ?- apropos(Word).
john
ben
% halt
$
dog.pl:
dog(john).
dog(ben).
run :- dog(X), write(X).
% OR:
% :- dog(X), write(X).
% To print only the first option automatically after consulting.
Then:
$ swipl
1 ?- [dog].
% dog compiled 0.00 sec, 4 clauses
true.
2 ?- run.
john
true ; # ';' is pressed by the user
ben
true.
3 ?-

Redirect SWI-Prolog console output to a file

I'm trying to write output from make_tests to a file, but nothing I've tried seems to insert the correct information in the output file.
I've looked at SWI documentaion at http://www.complang.tuwien.ac.at/SWI-Prolog/Manual/IO.html and have tried a whole bunch of those predicates but none have worked.
Here's what I'm trying to do:
:- use_module(library(test_wizard)).
init_test_file(FILE) :-
set_prolog_flag(log_query_file, FILE).
gen_test_in(FILE) :-
make_tests(lists, FILE, current_output).
So running this (in console) for example:
init_test_file('mytest.pro').
member(a, [a,b]).
gen_test_in('mytest.pro').
I get the following output (in console):
true.
6 ?- gen_test_in('r.pro').
:- begin_tests(lists).
test(member, [nondet]) :-
member(a, [a, b]).
:- end_tests(lists).
true.
How do I get this same output (starting at begin_tests and ending at end_tests in a text file?
I tried doing things like modifying gen_test_in to:
gen_test_in(FILE) :-
open(FILE, write, Out),
make_tests(lists, FILE, Out),
close(Out).
But I just get an empty text file.
You are messing up the arguments here. The library you are using, library(test_wizard), is meant for generating tests from queries. In the predicate you are using, make_tests/3, you have the following three arguments:
The module
The file from which the queries are read
The stream to which the generated tests are written
In the examples you use, you either set your output stream to be current_output (so standard output if you are on the top level), or, in the last example you give, you are opening the file you want to read for writing, and then pass the file and its handle to make_tests/3. Instead, if you have a file called queries.pl:
$ cat queries.pl
member(a, [a,b]).
member(X, [a,b]).
Then:
$ swipl
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.16-36-g42820df)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.
For help, use ?- help(Topic). or ?- apropos(Word).
?- use_module(library(test_wizard)).
true.
?- setup_call_cleanup(open('lists.plt', write, Out),
make_tests(lists, 'queries.pl', Out),
close(Out)).
Out = <stream>(0xe59ef0).
?- halt.
$ cat lists.plt
:- begin_tests(lists).
test(member, [nondet]) :-
member(a, [a, b]).
test(member, [all(A==[a, b])]) :-
member(A, [a, b]).
:- end_tests(lists).

running prolog as a script

So, I have some Prolog code that models variable assignments, such as in a programming language, and tries to see if they are compatible with one another. So,
assigned(X, X).
and(P, Q) :- P, Q.
or(P, Q) :- P.
or(P, Q) :- Q.
% and then we should test an expression like this:
and(assigned(X, 5), assigned(X, 6)).
So that last expression fails, since X can't be assigned to both 5 and 6.
Now, what I want to do is have this test a single expression (which can and should be hardcoded into the file), and then simply print out whether or not it's able to be satisfied. But it seems that SWIPL really wants me to run interactively. Ideally, something like this:
> ./test-assignments
false.
Surely this is possible? I'm at my wit's end on this.
There are several ways to get an SWI-Prolog program to run directly from the shell. You can look at this question and the answers:
How to run SWI-Prolog from the command line?
My personal preference now is to have a file example.pl like this:
:- set_prolog_flag(verbose, silent).
:- initialization(main).
main :-
format('Example script~n'),
current_prolog_flag(argv, Argv),
format('Called with ~q~n', [Argv]),
halt.
main :-
halt(1).
which I then run from the command line with:
$ swipl example.pl and a few arguments
Example script
Called with [and,a,few,arguments]
The initialization directive tells the interpreter which goal to evaluate after it loads the program: here it is main/0. The name main is a convention, it could have been called anything else.
See the linked question and answers for other options.

Resources