I'm trying to match some sentences (e.g. 001 [0,0,1], (1+(1/0)) ['(',1,+,'(',1,/,0,')',')'], and so on.
I've made myself following small DCG.
g3 --> s3.
s3 --> e3.
e3 --> eAdd.
e3 --> eMin.
e3 --> eMul.
e3 --> eDiv.
e3 --> n3.
eAdd --> ['('],e3,['+'],e3,[')'].
eMin --> ['('],e3,['-'],e3,[')'].
eMul --> ['('],e3,['*'],e3,[')'].
eDiv --> ['('],e3,['/'],e3,[')'].
n3 --> d3.
n3 --> n3,d3.
d3 --> [0].
d3 --> [1].
Now my problem is, it won't match with sentences using -,* or / but it works for recursive sentences using only +.
E.g:
phrase(g3,['(',1,'+','(',1,'+',1,')',')']).
Will work, but
phrase(g3,['(',1,'+','(',1,'/',1,')',')']).
Won't work.
Any help would be appreciated, thanks!
First of all, whenever you are using DCGs, consider to
:- set_prolog_flag(double_quotes, chars).
This permits to use a much more readable syntax. Here are the rules
and queries that change due to this convention.
:- set_prolog_flag(double_quotes, chars).
eAdd --> "(", e3, "+", e3, ")".
eMin --> "(", e3, "-", e3, ")".
eMul --> "(", e3, "*", e3, ")".
eDiv --> "(", e3, "/", e3, ")".
d3 --> "0".
d3 --> "1".
?- phrase(g3,"(1+(1+1))").
?- phrase(g3,"(1+(1/1))").
Note that already your first query has a problem, even if it succeeds.
This can be easily seen on the toplevel:
?- phrase(g3,"(1+(1+1))").
true
; resource_error(_). % ERROR: Out of local stack
So the toplevel insisted that there is something else apart from the
actual success. To narrow this down in a systematic manner I will use
a failure-slice which adds false to regular goals and
{false} within the grammar.
:- set_prolog_flag(double_quotes, chars).
g3 --> s3, {false}.
s3 --> e3, {false}.
e3 --> {false}, eAdd.
e3 --> {false}, eMin.
e3 --> {false}, eMul.
e3 --> {false}, eDiv.
e3 --> n3, {false}.
n3 --> {false}, d3.
n3 --> n3, {false}, d3.
?- phrase(g3,"(1+(1+1))"), false.
Because this tiny fragment loops, the entire program loops, too. Note
that + is no longer part of the program! The problem had nothing to
do with + at all.
Your problem is due to the rule
n3 --> n3,d3.
This is a so-called left recursive rule. It says that to match an n3, you must first match an n3, for which you must first match an n3, for which you must first, etc., and this never terminates.
Basically, you want every recursive grammar rule to first match some nonterminals before performing a recursive call. (Similarly, in the bodies of "normal" Prolog predicates, you should have other goals before any recursive call.)
If you change this rule to the right-recursive variant
n3 --> d3,n3.
your grammar becomes well-behaved:
?- phrase(g3,['(',1,'+','(',1,'+',1,')',')']).
true ;
false.
?- phrase(g3,['(',1,'+','(',1,'/',1,')',')']).
true ;
false.
?- length(L, 6), phrase(g3, L).
L = ['(', 0, +, 0, 0, ')'] ;
L = ['(', 0, +, 0, 1, ')'] ;
L = ['(', 0, +, 1, 0, ')'] ;
L = ['(', 0, +, 1, 1, ')'] ;
L = ['(', 1, +, 0, 0, ')'] ;
L = ['(', 1, +, 0, 1, ')'] ;
L = ['(', 1, +, 1, 0, ')'] ;
L = ['(', 1, +, 1, 1, ')'] ;
etc.
Here are a few old questions about left recursion in DCGs that might provide additional helpful information:
DCG and left recursion
Removing left recursion in DCG - Prolog
Removing left recursion grammar using DCG
Related
Is it possible to make a delta operator like this in sympy? Im not really sure how to code it. Should be really eazy if there exists a method.
I don't know if SymPy exposes something that could be useful to you. If not, we can create something raw.
Note: the following approach requires a bit of knowledge in Object Oriented Programming and the way SymPy treats things. This is a 5 minutes attempt, and it is not meant to be used in production (as a matter of fact, no test has been done over this code). There are many things that may not work as expected. But, for your case, it might work :)
One possible way is to define a "gradient" class, like this:
class Grad(Expr):
def __mul__(self, other):
return other.diff(*self.args)
def _latex(self, printer):
# create a latex representation to be visualize in Jupyter Notebook
return r"\frac{\partial}{%s}" % " ".join([r"\partial %s" % latex(t) for t in self.args])
We can create a gradient of something with respect to x by writing gx = Grad(x). Once gx is multiplied with some other thing, it returns the partial derivative of that thing with respect to x.
Then you would define your symbols/functions and matrices like this:
from sympy import *
init_printing()
var("x, y")
N1, N2, N3 = [s(x, y) for s in symbols("N1:4", cls=Function)]
A = Matrix(3, 2, [Grad(x), 0, 0, Grad(y), Grad(x), Grad(y)])
B = Matrix(2, 6, [N1, 0, N2, 0, N3, 0, 0, N1, 0, N2, 0, N3])
display(A, B)
Finally, you multiply the matrices together to obtain the symbolic results:
A * B
Eventually, you might want to create a function:
def delta_operator(x, y, N1, N2, N3):
A = Matrix(3, 2, [Grad(x), 0, 0, Grad(y), Grad(x), Grad(y)])
B = Matrix(2, 6, [N1, 0, N2, 0, N3, 0, 0, N1, 0, N2, 0, N3])
return A * B
So, whenever you have to apply that operator, you just execute delta_operator(x, y, N1, N2, N3) to obtain a result similar to above.
I can get the result to be true, but when I attempt to make it false I feel like it is in an endless loop.
repeat(L,N,Result):-
rHelp(L,N,[],Result).
rHelp(_,_,Result,Result).
rHelp([H|T],N,L1,L2):-
dupe(H,N,[],L3),
append(L1,L3,L4),
rHelp(T,N,L4,L2).
dupe(_,0,L,L).
dupe(H,N,L,Result):-
N1 is N-1,
append(L,[H],L1),
dupe(H,N1,L1,Result).
Example Test:
repeat( [a, b, c], 2, [a, a, b, b, c, c] )
repeat( [1, a, 2, b], 0, [ ] )
repeat( [1, 1, 2], 3, [1, 1, 1, 1, 1, 1, 2, 2, 2] )
which are all True. I am just trying to get a false result.
One reason it's hard to make your program fail is that it describes too many incorrect solutions:
?- repeat([a, b, c], 2, Result).
Result = [] ;
Result = [a, a] ;
Result = [a, a, b, b] ;
Result = [a, a, b, b, c, c] ;
% nontermination
The reason you accept too many solutions is the first clause of rHelp/4:
rHelp(_,_,Result,Result).
Here you say that for any input list, at any point in the computation where you have an intermediate result Result, that is a correct solution. But this is not the case. The intermediate result is only a complete result once you have exhausted the entire input list. This clause should be:
rHelp([], N, Result, Result).
Note that I found this essentially by pattern matching. Adjacent clause heads like
foo(_, Bar).
foo([H|T], Bar) :- ...
simply look incorrect. Why is the _ not an empty list? In most cases a predicate like this would have mutually exclusive patterns in the head, and here that is not the case.
With this fixed, we can try the test again:
?- repeat([a, b, c], 2, Result).
Result = [a, a, b, b, c, c] ;
% nontermination
Better! But it still goes searching for more solutions although there are none. This, too, is a case of clauses not being mutually exclusive:
dupe(_,0,L,L).
dupe(H,N,L,Result):-
N1 is N-1,
...
If the second argument is not 0, the second clause applies. If the second argument is 0, the first clause applies... but so does the second! After finding a solution using the first clause, Prolog will backtrack and execute the second clause with N = 0. Then N1 will become -1, and your program goes off recursively looking for negative infinity.
The fix is to add a guard N > 0 in the second clause. And with these two changes, the test works as desired:
?- repeat([a, b, c], 2, Result).
Result = [a, a, b, b, c, c] ;
false.
One general point to observe here is that it was easier to understand the behavior of your predicate by using less specific queries. There is no need to specify a fixed list for the Result argument: Leave it free and see what Prolog gives you!
I have the following Prolog from the book mastering Prolog, and I'm trying to learn some simple recursion.
mins_to_hours(In, H, M):-
In<60,
H = 0,
M is In.
mins_to_hours(In, H, M):-
In>=60,
In1 is In-60,
H1 is H+1,
mins_to_hours(In1, H1, M).
I'm not entirely sure why it doesn't work and I've been fiddling with it for hours. Any help even to point me in the right direction is much appreciated. Thanks in advance.
A major difficulty you are facing in this example is the so-called modedness of low-level arithmetic predicates. For example, let us try the most general query with the code you posted:
?- mins_to_hours(In, H, M).
ERROR: Arguments are not sufficiently instantiated
To get rid of this shortcoming, I first replace the low-level predicates with CLP(FD) constraints, which are available in all major Prolog systems and simplify reasoning over your code.
For this, I simply replace (<)/2 by (#<)/2, (is)/2 by (#=)/2 etc. (depending on your Prolog system, you may also still have to import a library for this):
mins_to_hours(In, H, M):-
In #< 60,
H = 0,
M #= In.
mins_to_hours(In, H, M):-
In #>= 60,
In1 #= In-60,
H1 #= H+1,
mins_to_hours(In1, H1, M).
Now, let us again try the most general query, where all arguments are fresh variables:
?- mins_to_hours(In, H, M).
In = M,
H = 0,
M in inf..59 ;
H = -1,
In in 60..119,
M+60#=In,
M in 0..59 ;
H = -2,
In in 120..179,
_5238+60#=In,
_5238 in 60..119,
M+60#=_5238,
M in 0..59 .
Here, it seems very odd that H can assume negative values!
Let us try a few concrete cases:
?- mins_to_hours(30, H, M).
H = 0,
M = 30 ;
false.
This still seems quite OK!
?- mins_to_hours(60, H, M).
H = -1,
M = 0 ;
false.
This already seems much less OK!
With a bit of practice, it is easy to see the reason: In the second clause, you are inadvertently confusing the roles of H and H1! Suppose we write the second clause like this:
mins_to_hours(In, H, M):-
In #>= 60,
In1 #= In-60,
H #= H1+1,
mins_to_hours(In1, H1, M).
Then we get:
?- mins_to_hours(60, H, M).
H = 1,
M = 0 ;
false.
And for two more cases:
?- mins_to_hours(500, H, M).
H = 8,
M = 20 ;
false.
?- mins_to_hours(1000, H, M).
H = 16,
M = 40 ;
false.
Seems pretty nice!
Note that if you stick to lower-level arithmetic, you cannot that easily correct the mistake: Using predicates like (<)/2 and (is)/2 requires that you also take into account the actual execution order of Prolog, and this is much too hard for almost all beginners. I highly recommend you use CLP(FD) constraints instead, since they let you readily try the effect of different goal orders, while keeping the relation correct and general.
I'm still new to Prolog, and I've encountered an error I have no idea how to fix.
I've written a simple exponentiation program that looks like this:
exp(b, 0, R) :- R is 1. % non-recursive case: exponent is 0
exp(0, e, R) :- R is 0. % non-recursive case: base is 0
exp(Base, Exponent, Result) :- % recurse if base and exponent are non-negative
Base >= 0,
Exponent >= 0,
E1 is Exponent-1,
exp(Base, E1, R1),
Result is Base*R1.
This compiles fine, but when I run it and give it a query like, say, exp(2, 4, X). I'm met with the following output:
?- exp(2, 4, X).
false.
Is there something I've done wrong? Or is it a matter of formatting the result in some way I'm unaware of?
You are confusing variables with atoms. It works as expected if you simple change the two nonrecusive clauses to:
exp(_, 0, 1).
exp(0, _, 0).
In fact, I recommend to change the whole program to use CLP(FD) constraints throughout:
exp(_, 0, 1).
exp(0, _, 0).
exp(Base, Exponent, Result):-
Base #>= 0,
Exponent #>= 0,
E1 #= Exponent-1,
exp(Base, E1, R1),
Result #= Base*R1.
Now for example the following at least yields a solution:
?- exp(2, X, 16).
X = 4
whereas we previously had:
?- exp(2, X, 16).
>=/2: Arguments are not sufficiently instantiated
Note also the most general query:
?- exp(X, Y, Z).
Y = 0,
Z = 1 ;
X = Z, Z = 0 ;
X = Z,
Y = 1,
Z in 0..sup ;
X = Z, Z = 0,
Y in 0..sup,
_G801+1#=Y,
_G801 in -1..sup .
I have a prolog program with given grammar:
sum --> [+], mult, sum | mult | num.
mult --> [*], num, xer.
xer --> [x] | [^], [x], num.
num --> [2] | [3] ... etc
I have an abstract tree representation of my expressions. For example: mul(num(2),var(x)) which equals [*,2,x] is valid.
I want to be able to create all expressions that satisfies a given x and solution. Using
allExpressions(Tree, X, Solution).
For example:
?- allExpressions(Tree, 2, 6)
Tree = mul(num(3),x)
Tree = sum(num(2),mul(num(2),var(x))
etc.
Due to my grammar it will obviously not be an unlimited set of equations for this.
I have already programmed an evaluation(Tree, X, Solution) which calculates the answer given the X-variable. So what I need help to is to generate the possible set of equations for given x-variable and solution.
Any ideas to how I approach this? Thanks
That's easy: Since all of your arithmetic operations can only increase the value of expressions, it is simple to limit the depth when searching for solutions. Simply describe inductively what a solution can look like. You can do it for example with SWI-Prolog's finite domain constraints for addition and multiplication like this:
:- use_module(library(clpfd)).
expression(var(x), X, X).
expression(num(N), _, N) :- phrase(num, [N]).
expression(mul(A,B), X, N) :-
N1 * N2 #= N,
N1 #> 1,
N2 #> 1,
expression(A, X, N1),
expression(B, X, N2).
expression(sum(A,B), X, N) :-
N1 + N2 #= N,
N1 #> 1,
N2 #> 1,
expression(A, X, N1),
expression(B, X, N2).
I leave the other operations as an exercise.
Example query and some results:
?- expression(Tree, 2, 6).
Tree = mul(var(x), num(3)) ;
Tree = mul(num(2), num(3)) ;
[...solutions omitted...]
Tree = sum(num(2), mul(num(2), var(x))) ;
Tree = sum(num(2), mul(num(2), num(2))) ;
[...solutions omitted...]
Tree = sum(sum(num(2), num(2)), num(2)) ;
false.
+1 for using a clean, non-defaulty representation for expression trees (var(x), num(N) etc.), which lets you use pattern matching when reasoning about it.