Prolog parse tree generation fails - prolog

I have the following prolog rules.
b(b(true)) --> [true].
b(b(false)) --> [false].
b(b(E,[=],E)) --> e(E),[=],e(E).
b(b([not],B)) --> [not],b(B).
e(e(I)) --> i(I).
e(e(N)) --> n(N).
e(e(N,O,E)) --> n(N),o(O),e(E).
e(e(I,O,E)) --> i(I),o(O),e(E).
o(o(+)) --> [+].
o(o(-))--> [-].
o(o(*))--> [*].
o(o(/)) --> [/].
i(i(x)) --> [x].
i(i(y)) --> [y].
i(i(z)) --> [z].
i(i(u)) --> [u].
i(i(v)) --> [v].
n(n(0)) --> [0].
n(n(1)) --> [1].
n(n(2)) --> [2].
n(n(3)) --> [3].
n(n(4)) --> [4].
n(n(5)) --> [5].
n(n(6)) --> [6].
n(n(7)) --> [7].
n(n(8)) --> [8].
n(n(9)) --> [9].
But I dunno why
[6] 26 ?- b(A,[x,=,4],[]).
false
fails. I tried to debug the code. 4 is not getting matched with n(n(4)). I couldn't understand wat the problem is.

(You would have received an answer much earlier if you would have used the prolog tag instead)
So, how can we localize the error? Let's start with your query:
?- phrase(b(A),[x,=,4]).
false.
Bad!
Shall I really fire up a trace/debugger?
What you are currently asking is: What are the solutions for A for a well-formed sentence.
Alas, there is none.
Can't we ask Prolog a more general question?
So, dear Prolog - at least - do you know any sentence?
Please say a word!
?- phrase(b(A),L).
A = b(true), L = [true]
; A = b(false), L = [false]
; ... .
So there is something - I will remove the A, because we want to see the sentences, first.
?- phrase(b(_),L).
L = [true]
; L = [false]
; L = [x,=,x]
; L = [y,=,y]
; L = [z,=,z]
; L = [u,=,u]
; L = [v,=,v]
; L = [0,=,0]
; L = [1,=,1]
; L = [2,=,2]
; L = [3,=,3]
; L = [4,=,4]
; L = [5,=,5]
; L = [6,=,6]
; L = [7,=,7]
; L = [8,=,8]
; L = [9,=,9]
; L = [0,+,x,=,0,+,x]
; ... .
Do you see a pattern here?
Maybe we can refine this.
What are the sentences of length 3 you know of?
?- L = [_,_,_], phrase(b(_),L).
L = [x,=,x]
; L = [y,=,y]
; L = [z,=,z]
; L = [u,=,u]
; L = [v,=,v]
; L = [0,=,0]
; L = [1,=,1]
; L = [2,=,2]
; L = [3,=,3]
; L = [4,=,4]
; L = [5,=,5]
; L = [6,=,6]
; L = [7,=,7]
; L = [8,=,8]
; L = [9,=,9]
; L = [not,not,true]
; L = [not,not,false]
; false.
In other words: There are no other three word sentences than those.
Now, do you get it?
There is a rule for sentences with =:
b(b(E,[=],E)) -->
e(E),[=],e(E).
It requires that the expression on the left-hand side is the same as the expression on the right-hand side. Therefore only those sentences above.
When debugging a Prolog program, there is much less need to type (on the keyboard) test data than in other languages. Instead, use variables to let Prolog fill-in-the-variables. After all, Prolog is much faster on that than we are ; and it does not suffer CTS.

Related

Two DCG rules for `(ab)*`. Can it be one?

I want to generate or test strings obeying the Perl Regex (ab)*
The code below works perfectly well:
Generate
?- phrase_acceptable(Text,6).
Text = abababababab ;
false.
Test (or compress?)
?- phrase_acceptable("ababab",N).
[97,98,97,98,97,98]
N = 3
Enumerate possibilities
?- phrase_acceptable(T,N).
T = '',
N = 0 ;
T = ab,
N = 1 ;
T = abab,
N = 2 ;
T = ababab,
N = 3
...
However, this demands two clauses for acceptable//1 which are selected based on whether N is fresh or not. Can that be avoided? Using CLP(FD) doesn't help, as one has to check that N>=0 in any case to avoid infinite descent.
ff(X) :- var(X). % "freshvar(X)" using 2 letters, which is less annoying
bb(X) :- nonvar(X). % "notfreshvar(X)" using 2 letters, which is less annoying
acceptable(0) --> [].
acceptable(N) --> { bb(N), N>0, succ(Nm,N) }, `ab`, acceptable(Nm).
acceptable(N) --> { ff(N) }, `ab`, acceptable(Nm), { succ(Nm,N) }.
phrase_acceptable(Text,N) :-
bb(Text),!,
atom_codes(Text,Codes),
writeln(Codes),
phrase(acceptable(N),Codes,[]).
phrase_acceptable(Text,N) :-
ff(Text),!,
phrase(acceptable(N),Codes,[]),
atom_codes(Text,Codes).
How about this:
:- use_module(library(clpfd)).
acceptable(0) --> [].
acceptable(N1) --> `ab`, { N #= N1-1, N #>= 0 }, acceptable(N).
phrase_acceptable(Text, N):-
(nonvar(Text) -> atom_codes(Text, Codes) ; true),
N #>= 0,
phrase(acceptable(N), Codes, []),
(var(Text) -> atom_codes(Text, Codes) ; true).
Test cases:
?- phrase_acceptable(ababab,N).
N = 3 ;
false.
?- phrase_acceptable(Text,3).
Text = ababab ;
false.
?- phrase_acceptable(Text,N).
Text = '',
N = 0 ;
Text = ab,
N = 1 ;
Text = abab,
N = 2 ;
Text = ababab,
N = 3 .

Checking if a string is contained in a language (Prolog)

This is the CFG:
S -> T | V
T -> UU
U -> aUb | ab
V -> aVb | aWb
W -> bWa | ba
so this will accept some form of:
{a^n b^n a^m b^m | n,m >= 1} U {a^n b^m a^m b^n | n,m >= 1}
And here is the code I'm working with:
in_lang([]).
in_lang(L) :-
mapS(L), !.
mapS(L) :-
mapT(L) ; mapV(L),!.
mapT(L) :-
append(L1, mapU(L), L), mapU(L1), !.
mapU([a|T]) :-
((append(L1,[b],T), mapU(L1)) ; (T = b)),!.
mapV([a|T]) :-
((append(L1,[b],T), mapV(L1)) ;
(append(L1,[b],T), mapW(L1))),
!.
mapW([b|T]) :-
((append(L1,[a],T), mapW(L1)) ;
(T = a)),
!.
As of right now, this is returning false for the following three strings:
[a,a,b,b,a,b] // this should be true
[a,a,a,b,b,a,a,b,b,b] // this should be true as well
[a,a,a,b,b,a,b,b,b] // this one IS false
Any help or insight would be greatly appreciated, I'm not too comfortable with Prolog so debugging this by myself has been a challenge.
Simply use a dcg! And library(double_quotes).
:- set_prolog_flag(double_quotes, chars).
s --> t | v.
t --> u, u.
u --> "a",u,"b" | "ab".
v --> "a",v,"b" | "a",w,"b".
w --> "b",w,"a" | "ba".
?- use_module(library(double_quotes)).
?- length(L,N), phrase(s, L).
L = "abab", N = 4
; L = "abab", N = 4
; L = "aabbab", N = 6
; L = "abaabb", N = 6
; L = "aababb", N = 6
; L = "abbaab", N = 6
; L = "aaabbbab", N = 8
; L = "aabbaabb", N = 8
; L = "abaaabbb", N = 8
; L = "aaababbb", N = 8
; ... .
First, note that this code doesn't make sense:
... append(L1, mapU(L), L) ...
In Prolog there are predicates, not functions...
A CFG production rule (a non terminal) should 'eat' a number of tokens, and in Prolog this means you need at least 2 arguments: the input token list, and what remains after a production has successfully matched the relevant part of input.
That is, append/3 is not required: just pattern matching, performed by unification operator (=)/2
mapS(L1, L) :- mapT(L1,L) ; mapV(L1,L).
mapT(L1, L) :- mapU(L1,L2), mapU(L2,L).
mapU(L1, L) :- L1=[a|L2], mapU(L2,L3), L3=[b|L] ; L1=[a,b|L].
... complete the translation
and then call it:
?- mapS([a,a,b,b,a,b],R).
R = [] ;
false.
R = [] means the entire sequence has been matched...
In the definition of mapT, you are trying to use the "return value" of mapU as an argument to append. But mapU is a predicate, and predicates don't have return values.
Instead one typically writes a predicate with an unbound variable which the predicate binds to the desired "return value"; after the predciate has been proven, the now bound variable can be used in subsequent predicates.

Defining Prolog DCG with extra arguments

I am trying to define a Prolog DCG for the set of strings 0^N 1^M 2^N+M of length 2N + 2M for N, M >= 0 using extra arguments. An example of a correct string would be "011222" but not "012".
I have used the following code to create this DCG.
s --> a(N), b(M), c(N), c(M).
a(0) --> [].
a(succ(X)) --> [0], a(X).
b(0) --> [].
b(succ(X)) --> [1], b(X).
c(0) --> [].
c(succ(X)) --> [2], c(X).
When I run the query
s([0,1,1,2,2,2], []).
Prolog returns true as expected.
However when I run
s(X, []).
Prolog returns the following:
X = []
X = [1,2]
X = [1,1,2,2]
X = [1,1,1,2,2,2]
These are not valid strings. I think this may be because N and M are being decremented by the c predicate before prolog runs the a and b predicates. Is this the case? How could this be resolved?
Edit:
I've tried modifying the s production to this:
s --> a(N), b(M), c(NplusM), {NplusM is N + M}.
but that gives an error when running queries.
IMO the answers you are getting are correct!
I renamed your grammar from s to aN_bM_cNM and added two additional arguments, one for N, the other for M. Also, I renamed succ to s:
aN_bM_cNM(N, M) --> n_reps(N, 0), n_reps(M, 1), n_reps(N, 2), n_reps(M, 2).
n_reps( 0 , _) --> [].
n_reps(s(N), E) --> [E], n_reps(N, E).
Now let's run the query that #CapelliC gave. The goal length(Xs, _) ensures fair enumeration of the infinite solution set of aN_bM_cNM//2:
?- length(Xs, _), phrase(aN_bM_cNM(N,M), Xs).
( Xs = [] , N = 0 , M = 0
; Xs = [1,2] , N = 0 , M = s(0)
; Xs = [0,2] , N = s(0) , M = 0
; Xs = [1,1,2,2] , N = 0 , M = s(s(0))
; Xs = [0,1,2,2] , N = s(0) , M = s(0)
; Xs = [0,0,2,2] , N = s(s(0)) , M = 0
; Xs = [1,1,1,2,2,2] , N = 0 , M = s(s(s(0)))
; Xs = [0,1,1,2,2,2] , N = s(0) , M = s(s(0))
; Xs = [0,0,1,2,2,2] , N = s(s(0)) , M = s(0)
; Xs = [0,0,0,2,2,2] , N = s(s(s(0))), M = 0
; Xs = [1,1,1,1,2,2,2,2], N = 0 , M = s(s(s(s(0))))
...
To raise the lower bound of N or M, just state an additional goal of the form X = s(s(_)) (for a minimum value of 2).
In the following query both N and M are to be greater than 0:
?- N = s(_) , M = s(_) , length(Xs, _), phrase(aN_bM_cNM(N,M), Xs).
( N = s(0) , M = s(0) , Xs = [0,1,2,2]
; N = s(0) , M = s(s(0)) , Xs = [0,1,1,2,2,2]
; N = s(s(0)), M = s(0) , Xs = [0,0,1,2,2,2]
; N = s(0) , M = s(s(s(0))), Xs = [0,1,1,1,2,2,2,2]
...
You're misusing succ/2, maybe because you expect Prolog evaluates functions in head patterns. It doesn't. Then, try to replace your rules with
a(0) --> [].
a(Y) --> {succ(X,Y)}, [0], a(X).
etc etc
edit since succ/2 needs at least one argument instantiated to an integer, we could supply N,M to the DCG entry, or, using CLP(FD):
:- use_module(library(clpfd)).
s --> a(N), b(M), c(N), c(M).
a(0) --> [].
a(Y) --> {Y #= X-1}, [0], a(X).
b(0) --> [].
b(Y) --> {Y #= X-1}, [1], b(X).
c(0) --> [].
c(Y) --> {Y #= X-1}, [2], c(X).
but still, list' length must be provided. For example
?- length(L,_),phrase(s,L).
L = [] ;
L = [1, 2] ;
L = [0, 2] ;
L = [1, 1, 2, 2] ;
L = [0, 1, 2, 2] ;
L = [0, 0, 2, 2] ;
...

Prolog - How to find the maximum set of elements that their sum is equal to N

my game is about picking the max set of elements from a given list that their sum is N
example : L=[1,1,2,2,3,2,4,5,6], N = 6 , Sub List would be equal to [1,1,2,2]
I need a hint using constraint logic programming.
There is a library for Constrained Logic Programming in SWI-Prolog. It's called clpfd.
:-use_module(library(clpfd)).
Let's say that you'll have a variable for the length of the subsequence. Its domain goes from zero (corresponding to the empty subsequence) to the length of the list. In order to get the longest sequence first, values should be tried starting with the highest.
...
length(List, M),
L in 0..M,
labeling([max(L)],[L]),
...
Next, L can be used to build a list of L variables that would correspond to indices of elements from List. As these indices must be in ascending order, chain/2 can be used to create #</2 constraints between any two consecutive indices.
...
length(Indices, L),
Indices ins 1..M,
chain(Indices, #<),
...
Using these indices, a list with elements from List can be constructed. nth1/3 is useful here, but with a minor trick.
...
nth1a(List, N, E):-
nth1(N, List, E).
...
maplist(nth1a(List), Indices, SubSequence),
...
And the sum of that list must be N:
...
sum(SubSequence, #=, N)
...
As only the longest sequence is needed, once/1 can be used to stop after first solution is found.
Some example queries:
?- longest_subsequence([1,1,4,4,6], 9, S).
S = [1, 4, 4].
?- longest_subsequence([1,1,4,4,6], 11, S).
S = [1, 4, 6].
?- longest_subsequence([1,1,4,4,6], 21, S).
false.
As I am not sure if that's a homework or not, I won't post the full code here.
In this answer we use clpfd and a little lambda:
:- use_module([library(clpfd),
library(lambda)]).
Based on meta-predicate maplist/4 and the constraints (ins)/2 and sum/3 we define:
zs_selection_len_sum(Zs, Bs, L, S) :-
same_length(Zs, Bs),
Bs ins 0..1,
maplist(\Z^B^X^(X #= Z*B), Zs, Bs, Xs),
sum(Bs, #=, L),
sum(Xs, #=, S).
Sample queries using labeling/2 with option max/1:
?- zs_selection_len_sum([1,1,4,4,6],Bs,L,8), labeling([max(L)],Bs).
Bs = [1,1,0,0,1], L = 3
; Bs = [0,0,1,1,0], L = 2
; false.
?- zs_selection_len_sum([1,1,3,4,5],Bs,L,7), labeling([max(L)],Bs).
Bs = [1,1,0,0,1], L = 3
; Bs = [0,0,1,1,0], L = 2
; false.
?- zs_selection_len_sum([1,1,2,2,3,2,4,5,6],Bs,L,6), labeling([max(L)],Bs).
Bs = [1,1,0,1,0,1,0,0,0], L = 4
; Bs = [1,1,1,0,0,1,0,0,0], L = 4
; Bs = [1,1,1,1,0,0,0,0,0], L = 4
; Bs = [0,0,1,1,0,1,0,0,0], L = 3
; Bs = [0,1,0,0,1,1,0,0,0], L = 3
; Bs = [0,1,0,1,1,0,0,0,0], L = 3
; Bs = [0,1,1,0,1,0,0,0,0], L = 3
; Bs = [1,0,0,0,1,1,0,0,0], L = 3
; Bs = [1,0,0,1,1,0,0,0,0], L = 3
; Bs = [1,0,1,0,1,0,0,0,0], L = 3
; Bs = [1,1,0,0,0,0,1,0,0], L = 3
; Bs = [0,0,0,0,0,1,1,0,0], L = 2
; Bs = [0,0,0,1,0,0,1,0,0], L = 2
; Bs = [0,0,1,0,0,0,1,0,0], L = 2
; Bs = [0,1,0,0,0,0,0,1,0], L = 2
; Bs = [1,0,0,0,0,0,0,1,0], L = 2
; Bs = [0,0,0,0,0,0,0,0,1], L = 1
; false.

Converting to unambiguous grammar from ambiguous grammar

I've ambiguous context-free grammar which has products:
s --> [0],s,[1].
s --> [0],s.
s --> [].
It's of course ambiguous because for 00011 I can draw two others parsing trees. I have to write my grammar which is unambiguous grammar and describes the same language. My idea is:
s --> [0],s,[1].
s --> [0],a.
s --> [].
a --> [0],a.
a --> [].
It's good? And how I can prove it?
So how can you prove ambiguity? In Prolog, this is easily possible for concrete sentences:
?- length(Xs,N), bagof(t,phrase(s,Xs),[_,_|_]).
Xs = [0,0,1], N = 3
; Xs = [0,0,0,1], N = 4
; Xs = [0,0,0,0,1], N = 5
; Xs = [0,0,0,1,1], N = 5
; Xs = [0,0,0,0,0,1], N = 6
; Xs = [0,0,0,0,1,1], N = 6
; Xs = [0,0,0,0,0,0,1], N = 7
; ... .
This proves that there is ambiguity for concrete length and gives the relevant counterexample.
There is, however a caveat which might show only after some time: bagof/3 has to store the entire set of solutions somehow. So if this set is very large, bagof/3 might overflow. The following query avoids this bug at the price of getting redundant solutions:
?- length(Xs,N), phrase(s,Xs), bagof(t,phrase(s,Xs),[_,_|_]).
Xs = [0,0,1], N = 3
; Xs = [0,0,1], N = 3
; Xs = [0,0,0,1], N = 4
; Xs = [0,0,0,1], N = 4
; Xs = [0,0,0,1], N = 4
; Xs = [0,0,0,1,1], N = 5
; Xs = [0,0,0,1,1], N = 5
; Xs = [0,0,0,0,1], N = 5
; Xs = [0,0,0,1,1], N = 5
; Xs = [0,0,0,0,1], N = 5
; Xs = [0,0,0,0,1], N = 5
; Xs = [0,0,0,0,1], N = 5
; Xs = [0,0,0,0,1,1], N = 6
; ... .
with your improved grammar, the query loops. That means that the system cannot find a counterexample. At least not with a length below 1000 which is what I tested.
Some general remarks about writing DCGs in Prolog:
Try to put the recursive case last, this might save some space.
You might want to use double-quoted strings to represent terminals. See this answer for more.

Resources