Prolog program to return atoms in a proposition formula - prolog

I am a newbie to prolog and am trying to write a program which returns the atoms in a well formed propositional formula. For instance the query ats(and(q, imp(or(p, q), neg(p))), As). should return [p,q] for As. Below is my code which returns the formula as As. I dont know what to do to split the single F in ats in the F1 and F2 in wff so wff/2 never gets called. Please I need help to proceed from here. Thanks.
CODE
logical_atom( A ) :-
atom( A ),
atom_codes( A, [AH|_] ),
AH >= 97,
AH =< 122.
wff(A):- ground(A),
logical_atom(A).
wff(neg(A)) :- ground(A),wff(A).
wff(or(F1,F2)) :-
wff(F1),
wff(F2).
wff(and(F1,F2)) :-
wff(F1),
wff(F2).
wff(imp(F1,F2)) :-
wff(F1),
wff(F2).
ats(F, As):- wff(F), setof(F, logical_atom(F), As).

First, consider using a cleaner representation: Currently, you cannot distinguish atoms by a common functor. So, wrap them for example in a(Atom).
Second, use a DCG to describe the relation between a well-formed formula and the list of its atoms, like in:
wff_atoms(a(A)) --> [A].
wff_atoms(neg(F)) --> wff_atoms(F).
wff_atoms(or(F1,F2)) --> wff_atoms(F1), wff_atoms(F2).
wff_atoms(and(F1,F2)) --> wff_atoms(F1), wff_atoms(F2).
wff_atoms(imp(F1,F2)) --> wff_atoms(F1), wff_atoms(F2).
Example query and its result:
?- phrase(wff_atoms(and(a(q), imp(or(a(p), a(q)), neg(a(p))))), As).
As = [q, p, q, p].

This should do what you want. It extracts the unique set of atoms found in any arbitrary prolog term.
I'll leave it up to you, though, to determine what constitutes a "well formed propositional formula", as you put it in your problem statement (You might want to take a look at DCG's for parsing and validation).
The bulk of the work is done by this "worker predicate". It simply extracts, one at a time via backtracking, any atoms found in the parse tree and discards anything else:
expression_atom( [T|_] , T ) :- % Case #1: head of list is an ordinary atom
atom(T) , % - verify that the head of the list is an atom.
T \= [] % - and not an empty list
. %
expression_atom( [T|_] , A ) :- % Case #2: head of listl is a compound term
compound(T) , % - verify that the head of the list is a compound term
T =.. [_|Ts] , % - decompose it, discarding the functor and keeping the arguments
expression_atom(Ts,A) % - recurse down on the term's arguments
. %
expression_atom( [_|Ts] , A ) :- % Finally, on backtracking,
expression_atom(Ts,A) % - we simply discard the head and recurse down on the tail
. %
Then, at the top level, we have this simple predicate that accepts any [compound] prolog term and extracts the unique set of atoms found within by the worker predicate via setof/3:
expression_atoms( T , As ) :- % To get the set of unique atoms in an arbitrary term,
compound(T) , % - ensure that's its a compound term,
T =.. [_|Ts] , % - decompose it, discarding the functor and keeping the arguments
setof(A,expression_atom(Ts,A),As) % - invoke the worker predicate via setof/3
. % Easy!

I'd approach this problem using the "univ" operator =../2 and explicit recursion. Note that this solution will not generate and is not "logically correct" in that it will not process a structure with holes generously, so it will produce different results if conditions are reordered. Please see #mat's comments below.
I'm using cuts instead of if statements for personal aesthetics; you would certainly find better performance with a large explicit conditional tree. I'm not sure you'd want a predicate such as this to generate in the first place.
Univ is handy because it lets you treat Prolog terms similarly to how you would treat a complex s-expression in Lisp: it converts terms to lists of atoms. This lets you traverse Prolog terms as lists, which is handy if you aren't sure exactly what you'll be processing. It saves me from having to look for your boolean operators explicitly.
atoms_of_prop(Prop, Atoms) :-
% discard the head of the term ('and', 'imp', etc.)
Prop =.. [_|PropItems],
collect_atoms(PropItems, AtomsUnsorted),
% sorting makes the list unique in Prolog
sort(AtomsUnsorted, Atoms).
The helper predicate collect_atoms/2 processes lists of terms (univ only dismantles the outermost layer) and is mutually recursive with atoms_of_prop/2 when it finds terms. If it finds atoms, it just adds them to the result.
% base case
collect_atoms([], []).
% handle atoms
collect_atoms([A|Ps], [A|Rest]) :-
% you could replace the next test with logical_atom/1
atom(A), !,
collect_atoms(Ps, Rest).
% handle terms
collect_atoms([P|Ps], Rest) :-
compound(P), !, % compound/1 tests for terms
atoms_of_prop(P, PAtoms),
collect_atoms(Ps, PsAtoms),
append(PAtoms, PsAtoms, Rest).
% ignore everything else
collect_atoms([_|Ps], Rest) :- atoms_of_prop(Ps, Rest).
This works for your example as-is:
?- atoms_of_prop(ats(and(q, imp(or(p, q), neg(p))), As), Atoms).
Atoms = [p, q].

Related

How to do recursion in a L-system inspired rewrite System, without DCG

I am trying to write a tiny recursive rewrite system inspired by Aristid Lindenmayers L-System basically to learn Prolog as well as to think about generative concepts in Prolog. I would like to achieve this without DCG. Due to the initial generate. and output predicate with side effects it is not a 100% pure prolog idea. Don´t hesitate to take the concept apart.
My main problem is at the end of the listing. Matching the rule for every element in the original list and creating a new list with the result of each substitution.
[a] the Axiom becomes [a,b] becomes [a,b,a] and so on. Or better as a list of lists
[[a,b],[a]] to keep it more flexible and comprehensible and then flatten it later?
Basic example without constants, which could be added in a similar way. The Axiom is just used one time at the start. The idea is to encode the rule name or symbol to exchange and the symbols it should be exchanged with, as a fact/relation. Start with generate. would repeat it 20 times with a counter.
% The rules
axiom(a, [a]).
rule(a, [a, b]).
rule(b, [a]).
% Starts the program
generate :-
axiom(a, G),
next_generation(20, G).
% repeats it until counter 0.
next_generation(0, _) :- !.
next_generation(N, G) :-
output(G),
linden(G, Next),
succ(N1, N),
next_generation(N1, Next).
% Concatenates the list to one string for the output
output(G) :-
atomic_list_concat(G,'',C),
writeln(C).
% Here I am stuck, the recursive lookup and exchange.
% How do I exchange each element with the according substitution to a new list
linden([],[]). % Empty list returns empty list.
linden([R],Next) :- % List with just one Element, e.g. the axiom
rule(R, Next). % Lookup the rule and List to exchange the current
linden([H|T], Next) :- % If more than one Element is in the original list
rule(H,E), % match the rule for the current Head/ List element
% ????? % concatenate the result with the result of former elements
linden(T, Next). % recursive until the original list is processed.
% Once this is done it returns the nw list to next_generation/2
Yes, you want lists of lists. Each character can then map cleanly to one corresponding expansion list:
linden([], []).
linden([H|T], [E | Next]) :-
rule(H, E),
linden(T, Next).
(This is simpler and shorter than with a DCG for the same thing, BTW.)
For example:
?- linden([a], Expansion).
Expansion = [[a, b]].
?- linden([a, b, a], Expansion).
Expansion = [[a, b], [a], [a, b]].
Then flatten this to a flat list before expanding the next generation.

prolog finding cardinality of a list

I have written a Prolog code to find the cardinality of a list ie number of distinct elements. It gives correct output but it runs multiple times and I cant seem to get my head around it. I have used the debugger but cant understand whats wrong
member(A, [A|_]).
member(A, [_|L]) :- member(A, L).
crdnlty([],0).
crdnlty([A|R],N) :-
(
\+ member(A, R),
crdnlty(R, N1),
N is N1+1
);
(
member(A, R),
crdnlty(R, N)
).
member checks if A is present in the remaining list.
if its not present ie it is the last occurrence of that element cardinality is increased by 1.
for example if i run the query
crdnlty([1,2,1,1], N).
it returns
N = 2 ;
N = 2 ;
false.
but it should return
N = 2 ;
false.
This is not answer but just a testing suggestion that doesn't fit in a comment.
Besides the unwanted duplicated solution, there's also the question on how to test the predicate. A simple alternative solution is to use the ISO Prolog standard predicate sort/2 and the de facto standard predicate length/2. The alternative solution could be:
cardinality(List, Cardinality) :-
sort(List, Sorted),
length(Sorted, Cardinality).
We can use this alternative solution to define a property that your solution must comply with that allows to QuickCheck your solution (ignoring for now the unwanted non-determinism):
property(List) :-
once(crdnlty(List, C)),
sort(List, S),
length(S, C).
Using the QuickCheck implementation provided by Logtalk's lgtunit tool (which you can run in most Prolog systems; in this example I will be using GNU Prolog):
$ gplgt
...
| ?- {lgtunit(loader)}.
...
% (0 warnings)
(578 ms) yes
| ?- lgtunit::quick_check(property(+list(integer)), [n(2000)]).
% 2000 random tests passed
(1589 ms) yes
Of course, QuickCheck can show bugs but cannot prove their absence. That said, a distinctive feature of Logtalk's QuickCheck implementation is that it tries trivial/corner cases for the specified types before generating random values. This help in ensuring that the random testing will not miss obvious test cases (as we illustrate next).
What happens if we test instead the solution provided by Scott Hunter?
| ?- lgtunit::quick_check(property(+list(integer)), [n(2000)]).
* quick check test failure (at test 1 after 0 shrinks):
* property([])
no
In fact, his solution doesn't take into account that the list may be empty. Assuming that's considered a bug, adding the missing clause:
crdnlty([], 0).
Re-testing:
| ?- lgtunit::quick_check(property(+list(integer)), [n(2000)]).
% 2000 random tests passed
(1509 ms) yes
It might be better to build a list of distinct elements & yield its length for the cardinality:
crdnlty([A|R],N) :- distinct(R,N,[A],1).
% distinct(L,N,DL,DN): There are N distinct values in list L+DL,
% assuming there are DN distinct values in list DL alone.
distinct([],N,_,N).
distinct([A|R],N,DL,DN) :-
(
\+ member(A, DL),
DN1 is DN+1,
distinct(R, N, [A|DL], DN1)
);
(
member(A, DL),
distinct(R, N, DL, DN)
).

Prolog return a list which contains only elements which are equal to head of the list

Hello I would like to ask a doubt I have with the following code:
principio([],[]).
principio([H],[H]).
principio([H,_|_],[H]).
principio([H,H|C],P) :-
principio([H|C],R),P=[H|R].
I would like a way to get from:
?- principio([222,333,101,202,12,222,13,222],X).
X = [222,222,222]
But in this moment I get just the head:
X = [222]
So, to keep it clear I'd like: all successive occurrences of the first element as a list.
My doubt is what does this assignment P=[H|R] why not to put just:
principio([H,H|C],P) :-
principio([H|C],P)
Also, how would you try to modify this to get the result I asked for?
Thank you
Here is two ways how you can narrow down the problem. 1st, start from an unexpectedly failing query. 2nd, start from a query that should fail but rather succeeds.
1st Diagnose unexpected incompleteness
Determine a most specific failing query
?- principio([222,333,101,202,12,222,13,222],[222,222,222]).
false.
Generalize the query
... as much as possible. I could do this manually, or I could let Prolog do the work for me. Here I use library(diadem):
?- use_module(diadem).
true.
?- principio([222,333,101,202,12,222,13,222],[222,222,222]).? Gen.
Gen = principio([222, 333|_], [_, _|_])
; Gen = (dif(A100, B100), principio([A100, B100|_], [_, _|_]))
; ... .
In other words: Not only does your original query fail, but also this generalization fails! Here, we only insist that the first two elements are different, and that the resulting list contains at least two elements — no matter which!
?- dif(X, Y), principio([X,Y|_],[_,_|_]).
Generalize your program
:- op(950, fy, *).
* _P_0.
principio([], _/*[]*/).
principio([_H], _/*[H]*/).
principio([H,_|_],[H]).
principio([H,H|C],P) :-
* principio([H|C],R),
* P=[H|R].
The error must reside in the little remaining part of your program. No need to read any further!
The problem is that for a list starting with two different elements you only have the clause principio([H,_|_],[H]).. So this part has to be generalized somehow.
2nd Diagnose unexpected unsoundness
Another way of finding the error would be to start with the unexpected solution:
?- principio([222,333,101,202,12,222,13,222],[222]).
true. % incorrect !!
And then reduce the size of the query as much as possible.
?- principio([222,222],[222]).
true. % incorrect !!
Now, specialize your program inserting false as long as above query succeeds:
principio([],[]) : - false.
principio([H],[H]) :- false.
principio([H,_|_],[H]).
principio([H,H|C],P) :- false,
principio([H|C],R),
P=[H|R].
The remaining visible part is the culprit! We have to revise it. What it says is:
Any list starting with two elements corresponds to the list with the first element only.
principio([],[]).
principio([H],[H]).
principio([H,D|Xs], [H|Hs]) :-
dif(H,D),
principio([H|Xs],[H|Hs]).
principio([H,H|Xs],[H|Hs]) :-
principio([H|Xs],Hs).
In addition to the very nice answer provided by #false (+s(0)), I would point out the possibility to use DCGs for the task. They usually yield easily readable code when describing lists (see comments beside the grammar rules):
principio([H|T],Hs) :-
phrase(heads([H|T],H),Hs).
heads([],_H) --> % in the empty list
[]. % there's no element matching H
heads([H|Xs],H) --> % if the head of the list matches H
[H], % it's in the list
heads(Xs,H). % same for the tail
heads([X|Xs],H) --> % if the head of the list is
{dif(X,H)}, % different from H it's not in the list
heads(Xs,H). % same for the tail
Thus your example query yields the desired result:
?- principio([222,333,101,202,12,222,13,222],X).
X = [222,222,222] ? ;
no

Find the minimum in a mixed list in Prolog

I am new to prolog, I am just learning about lists and I came across this question. The answer works perfect for a list of integers.
minimo([X], X) :- !.
minimo([X,Y|Tail], N):-
( X > Y ->
minimo([Y|Tail], N)
;
minimo([X|Tail], N)
).
How can I change this code to get the smallest int from a mixed list?
This
sint([a,b,3,2,1],S)
should give an answer:
S=1
you could just ignore the problem, changing the comparison operator (>)/2 (a binary builtin predicate, actually) to the more general (#>)/2:
minimo([X], X) :- !.
minimo([X,Y|Tail], N):-
( X #> Y ->
minimo([Y|Tail], N)
;
minimo([X|Tail], N)
).
?- minimo([a,b,3,2,1],S).
S = 1.
First of all, I don't think the proposed implementation is very elegant: here they pass the minimum found element thus far by constructing a new list each time. Using an additional parameter (we call an accumulator) is usually the way to go (and is probably more efficient as well).
In order to solve the problem, we first have to find an integer. We can do this like:
sint([H|T],R) :-
integer(H),
!,
sint(T,H,R).
sint([_|T],R) :-
sint(T,R).
So here we check if the head H is an integer/1. If that is the case, we call a predicate sint/3 (not to be confused with sint/2). Otherwise we call recursively sint/2 with the tail T of the list.
Now we still need to define sint/3. In case we have reached the end of the list [], we simply return the minum found thus far:
sint([],R,R).
Otherwise there are two cases:
the head H is an integer and smaller than the element found thus far, in that case we perform recursion with the head as new current minimum:
sint([H|T],M,R):
integer(H),
H < M,
!,
sint(T,H,R).
otherwise, we simply ignore the head, and perform recursion with the tail T.
sint([_|T],M,R) :-
sint(T,M,R).
We can put the recursive clauses in an if-then-else structure. Together with the earlier defined predicate, the full program then is:
sint([H|T],R) :-
integer(H),
!,
sint(T,H,R).
sint([_|T],R) :-
sint(T,R).
sint([],R,R).
sint([H|T],M,R):
(
(integer(H),H < M)
-> sint(T,H,R)
; sint(T,M,R)
).
The advantage of this approach is that filtering and comparing (to obtain the minimum) is done at the same time, so we only iterate once over the list. This will usually result in a performance boost since the "control structures" are only executed once: more is done in an iteration, but we only iterate once.
We can generalize the approach by making the filter generic:
filter_minimum(Filter,[H|T],R) :-
Goal =.. [Filter,H],
call(Goal),
!,
filter_minimum(Filter,T,H,R).
filter_minimum(Filter,[_|T],R) :-
filter_minimum(Filter,T,R).
filter_minimum(_,[],R,R).
filter_minimum(Filter,[H|T],M,R) :-
Goal =.. [Filter,H],
(
(call(Goal),H < M)
-> filter_minimum(Filter,T,H,R)
; filter_minimum(Filter,T,M,R)
).
You can then call it with:
filter_minimum(integer,[a,b,3,2,1],R).
to filter with integer/1 and calculate the minimum.
You could just write a predicate that returns a list with the numbers and the use the above minimo/2 predicate:
only_numbers([],[]).
only_numbers([H|T],[H|T1]):-integer(H),only_numbers(T,T1).
only_numbers([H|T],L):- \+integer(H),only_numbers(T,L).
sint(L,S):-only_numbers(L,L1),minimo(L1,S).

studying for prolog/haskell programming exam

I starting to study for my upcoming exam and I'm stuck on a trivial prolog practice question which is not a good sign lol.
It should be really easy, but for some reason I cant figure it out right now.
The task is to simply count the number of odd numbers in a list of Int in prolog.
I did it easily in haskell, but my prolog is terrible. Could someone show me an easy way to do this, and briefly explain what you did?
So far I have:
odd(X):- 1 is X mod 2.
countOdds([],0).
countOdds(X|Xs],Y):-
?????
Your definition of odd/1 is fine.
The fact for the empty list is also fine.
IN the recursive clause you need to distinguish between odd numbers and even numbers. If the number is odd, the counter should be increased:
countOdds([X|Xs],Y1) :- odd(X), countOdds(Xs,Y), Y1 is Y+1.
If the number is not odd (=even) the counter should not be increased.
countOdds([X|Xs],Y) :- \+ odd(X), countOdds(Xs,Y).
where \+ denotes negation as failure.
Alternatively, you can use ! in the first recursive clause and drop the condition in the second one:
countOdds([X|Xs],Y1) :- odd(X), !, countOdds(Xs,Y), Y1 is Y+1.
countOdds([X|Xs],Y) :- countOdds(Xs,Y).
In Prolog you use recursion to inspect elements of recursive data structs, as lists are.
Pattern matching allows selecting the right rule to apply.
The trivial way to do your task:
You have a list = [X|Xs], for each each element X, if is odd(X) return countOdds(Xs)+1 else return countOdds(Xs).
countOdds([], 0).
countOdds([X|Xs], C) :-
odd(X),
!, % this cut is required, as rightly evidenced by Alexander Serebrenik
countOdds(Xs, Cs),
C is Cs + 1.
countOdds([_|Xs], Cs) :-
countOdds(Xs, Cs).
Note the if, is handled with a different rule with same pattern: when Prolog find a non odd element, it backtracks to the last rule.
ISO Prolog has syntax sugar for If Then Else, with that you can write
countOdds([], 0).
countOdds([X|Xs], C) :-
countOdds(Xs, Cs),
( odd(X)
-> C is Cs + 1
; C is Cs
).
In the first version, the recursive call follows the test odd(X), to avoid an useless visit of list'tail that should be repeated on backtracking.
edit Without the cut, we get multiple execution path, and so possibly incorrect results under 'all solution' predicates (findall, setof, etc...)
This last version put in evidence that the procedure isn't tail recursive. To get a tail recursive procedure add an accumulator:
countOdds(L, C) :- countOdds(L, 0, C).
countOdds([], A, A).
countOdds([X|Xs], A, Cs) :-
( odd(X)
-> A1 is A + 1
; A1 is A
),
countOdds(Xs, A1, Cs).

Resources