My ultimate goal is to load a set of propositional formulas in to Prolog from a file in order to deduce some facts. Suppose I have the propositional formula:
p implies not(q).
In Prolog this would be:
not(q) :- p
Prolog does not seem to like the not operator in the head of the rule. I get the following error:
'$record_clause'/2: No permission to redefine built-in predicate `not/1'
Use :- redefine_system_predicate(+Head) if redefinition is intended
I know two ways to rewrite the general formula for p implies q. First, use the fact that the contrapositive is logically equivalent.
p implies q iff not(q) implies not(p)
Second, use the fact that p implies q is logically equivalent to not(p) or q (the truth tables are the same).
The first method leads me to my current problem. The second method is then just a conjunction or disjunction. You cannot write only conjunctions and disjunctions in Prolog as they are not facts or rules.
What is the best way around my problem so that I can express p implies not(q)?
Is it possible to write all propositional formulas in Prolog?
EDIT: Now I wish to connect my results with other propositional formulae. Suppose I have the following rule:
something :- formula(P, Q).
How does this connect? If I enter formula(false, true) (which evaluates to true) into the interpreter, this does not automatically make something true. Which is what I want.
p => ~q === ~p \/ ~q === ~( p /\ q )
So we can try to model this with a Prolog program,
formula(P,Q) :- P, Q, !, fail.
formula(_,_).
Or you can use the built-in \+ i.e. "not", to define it as formula(P,Q) :- \+( (P, Q) ).
This just checks the compliance of the passed values to the formula. If we combine this with domain generation first, we can "deduce" i.e. generate the compliant values:
13 ?- member(Q,[true, false]), formula(true, Q). %// true => ~Q, what is Q?
Q = false.
14 ?- member(Q,[true, false]), formula(false, Q). %// false => ~Q, what is Q?
Q = true ;
Q = false.
You are using the wrong tool. Try Answer Set Programming.
Related
I am developing a path finding algorithm in Prolog, giving all nodes accessible by a path from a starting node. To avoid duplicate paths, visited nodes are kept in a list.
Nodes and neighbors are defined as below:
node(a).
node(b).
node(c).
node(d).
node(e).
edge(a,b).
edge(b,c).
edge(c,d).
edge(b,d).
neighbor(X,Y) :- edge(X,Y).
neighbor(X,Y) :- edge(Y,X).
The original algorithm below works fine:
path2(X,Y) :-
pathHelper(X,Y,[X]).
pathHelper(X,Y,L) :-
neighbor(X,Y),
\+ member(Y,L).
pathHelper(X,Y,H) :-
neighbor(X,Z),
\+ member(Z,H),
pathHelper(Z,Y,[Z|H]).
This works fine
[debug] ?- path2(a,X).
X = b ;
X = c ;
X = d ;
X = d ;
X = c ;
false.
however, when changing the order of the two clauses in the second definition, such as below
pathHelper(X,Y,L) :-
\+ member(Y,L),
neighbor(X,Y).
When trying the same here, swipl returns the following:
[debug] ?- path2(a,X).
false.
The query doesn't work anymore, and only returns false. I have tried to understand this through the tracecommand, but still can't make sense of what exactly is wrong.
In other words, I am failing to understand why the order of neighbor(X,Y)and \+ member(Y,L)is crucial here. It makes sense to have neighbor(X,Y) first in terms of efficiency, but not in terms of correctness to me.
You are now encountering the not so clean-cut borders of pure Prolog and its illogical surroundings. Welcome to the real world.
Or rather, not welcome! Instead, let's try to improve your definition. The key problem is
\+ member(Y, [a]), Y = b.
which fails while
Y = b, \+ member(Y,[a]).
succeeds. There is no logic to justify this. It's just the operational mechanism of Prolog's built-in (\+)/1.
Happily, we can improve upon this. Enter non_member/2.
non_member(_X, []).
non_member(X, [E|Es]) :-
dif(X, E),
non_member(X, Es).
Now,
?- non_member(Y, [a]).
dif(Y,a).
Mark this answer, it says: Yes, Y is not an element of [a], provided Y is different from a. Think of the many solutions this answer includes, like Y = 42, or Y = b and infinitely many more such solutions that are not a. Infinitely many solutions captured in nine characters!
Now, both non_member(Y, [a]), Y = b and Y = b, non_member(Y, [a]) succeed. So exchanging them has only influence on runtime and space consumption. If we are at it, note that you check for non-memberness in two clauses. You can factor this out. For a generic solution to this, see closure/3. With it, you simply say: closure(neighbor, A,B).
Also consider the case where you have only edge(a,a). Your definition fails here for path2(a,X). But shouldn't this rather succeed?
And the name path2/2 is not that fitting, rather reserve this word for an actual path.
The doubt you have is related to how prolog handle negation. Prolog uses negation as failure. This means that, if prolog has to negate a goal g (indicate it with not(g)), it tries to prove g by executing it and then, if the g fails, not(g) (or \+ g, i.e. the negation of g) succeeds and viceversa.
Keep in mind also that, after the execution of not(g), if the goal has variables, they will not be instantiated. This because prolog should instantiate the variables with all the terms that makes g fail, and this is likely an infinite set (for example for a list, not(member(A,[a]) should instantiate the variable A with all the elements that are not in the list).
Let's see an example. Consider this simple program:
test:-
L = [a,b,c],
\+member(A,L),
writeln(A).
and run it with ?- trace, test. First of all you get a Singleton variable in \+: A warning for the reason i explained before, but let's ignore it and see what happens.
Call:test
Call:_5204=[a, b]
Exit:[a, b]=[a, b]
Call:lists:member(_5204, [a, b])
Exit:lists:member(a, [a, b]) % <-----
Fail:test
false
You see at the highlighted line that the variable A is instantiated to a and so member/2 succeeds and so \+ member(A,L) is false.
So, in your code, if you write pathHelper(X,Y,L) :- \+ member(Y,L), neighbor(X,Y)., this clause will always fail because Y is not sufficiently instantiated. If you swap the two terms, Y will be ground and so member/2 can fail (and \+member succeeds).
| ?- [user].
compiling user for byte code...
formula_0(P, Q):- (P; Q), \+ P.
user compiled, 2 lines read - 768 bytes written, 37208 ms
yes
| ?- formula_0(P, Q).
uncaught exception: error(instantiation_error,formula_0/2)
All I basically want to do is to ask is the set of expressions {P or Q, ~P} satisfiable?
But the error message is not helping here...
PS. The answer should be "yes", this formula is satisfied when P = false and Q = true.
The reason you get an instantiation error is that too little is known about P and Q to say anything about them at the time they are used as goals. You are right that when you ask for example:
?- G.
then G = true is a solution that makes the query succeed. But so is for example G = (a=a) because a=a is also true. Since it is not possible to enumerate all goals G that succeed, you get an instantiation error. But notice for example that when you explicitly give a binding, you get the result you expect:
?- G = true, G.
G = true.
So, you should provide a set of values you are interested in:
?- maplist(boolean, [P,Q]), formula(P, Q).
and define for example:
boolean(true).
boolean(false).
to obtain concrete solutions. Or use constraints, which let you constrain the domain of variables before using them.
EDIT: Since there was some discussion about this, I go into more detail. The main question that arose is: Why does the query
?- Q.
not succeed with the sole solution
Q = true.
since obviously, true succeeds and is thus a valid solution? Answer: There are other possible answers as well, since true is not the only goal that succeeds. For example, the conjunction (true,true) succeeds as well. Suppose now that Q = true were the only solution to the above query, then it would be the case that:
?- Q, Q = (true, true).
fails (since dif(true, (true,true)) is itself true), but simply exchanging the goals like
?- Q = (true,true), Q.
succeeds because otherwise ?- true, true would also have to fail and that cannot be the case. This would violate commutativity of conjunction already for the most basic predicate (unification).
Note that while true and (true,true) both succeed when executed as goals, they are obviously different terms and cannot replace each other in general. Similarly, the term append([], [], []) is different from the term true, although both succeed when executed as goals. You therefore get an instantiation error, since too little is known about Q in a query like ?- Q. to give useful results.
Use clpb for constraint logic programming over Booleans.
:- use_module(library(clpb)).
Sample query:
?- sat((P+Q) * ~P).
P = 0, Q = 1. % succeeds deterministically
Gnu Prolog supports the 'naked variable' call, a syntactic feature that allows to write code like you show in formula_0/2. But when it come to executing it, variables must be bound !
| ?- P.
uncaught exception: error(instantiation_error,top_level/0)
| ?- P=write(1), P.
1
P = write(1)
then just use callables:
| ?- formula_0(fail,true).
yes
I have a manually made DCG rule to select idiomatic phrases
over single words. The DCG rule reads as follows:
seq(cons(X,Y), I, O) :- noun(X, I, H), seq(Y, H, O), \+ noun(_, I, O).
seq(X) --> noun(X).
The first clause is manually made, since (:-)/2 is used instead
of (-->)/2. Can I replace this manually made clause by
some clause that uses standard DCG?
Best Regards
P.S.: Here is some test data:
noun(n1) --> ['trojan'].
noun(n2) --> ['horse'].
noun(n3) --> ['trojan', 'horse'].
noun(n4) --> ['war'].
And here are some test cases, the important test case is the first test case, since it does only
deliver n3 and not cons(n1,n2). The behaviour of the first test case is what is especially desired:
?- phrase(seq(X),['trojan','horse']).
X = n3 ;
No
?- phrase(seq(X),['war','horse']).
X = cons(n4,n2) ;
No
?- phrase(seq(X),['trojan','war']).
X = cons(n1,n4) ;
No
(To avoid collisions with other non-terminals I renamed your seq//1 to nounseq//1)
Can I replace this manually made clause by some clause that uses standard DCG?
No, because it is not steadfast and it is STO (details below).
Intended meaning
But let me start with the intended meaning of your program. You say you want to select idiomatic phrases over single words. Is your program really doing this? Or, to put it differently, is your definition really unique? I could now construct a counterexample, but let Prolog do the thinking:
nouns --> [] | noun(_), nouns.
?- length(Ph, N), phrase(nouns,Ph),
dif(X,Y), phrase(nounseq(X),Ph), phrase(nounseq(Y),Ph).
Ph = [trojan,horse,trojan], N = 3, X = cons(n1,cons(n2,n1)), Y = cons(n3,n1)
; ...
; Ph = [trojan,horse,war], N = 3, X = cons(n3,n4), Y = cons(n1,cons(n2,n4))
; ... .
So your definition is ambiguous. What you essentially want (probably) is some kind of rewrite system. But those are rarely defined in a determinate manner. What, if two words overlap like an additional noun(n5) --> [horse, war]. etc.
Conformance
A disclaimer up-front: Currently, the DCG document is still being developed — and comments are very welcome! You find all material in this place. So strictly speaking, there is at the current point in time no notion of conformance for DCG.
Steadfastness
One central property a conforming definition must maintain is the property of steadfastness. So before looking into your definition, I will compare two goals of phrase/3 (running SWI in default mode).
?- Ph = [], phrase(nounseq(cons(n4,n4)),Ph0,Ph).
Ph = [], Ph0 = [war,war]
; false.
?- phrase(nounseq(cons(n4,n4)),Ph0,Ph), Ph = [].
false.
?- phrase(nounseq(cons(n4,n4)),Ph0,Ph).
false.
Moving the goal Ph = [] at the end, removes the only solution. Therefore, your definition is not steadfast. This is due to the way how you handle (\+)/1: The variable O must not occur within the (\+)/1. But on the other hand, if it does not occur within (\+)/1 you can only inspect the beginning of a sentence. And not the entire sentence.
Subject to occurs-check property
But the situation is worse:
?- set_prolog_flag(occurs_check,error).
true.
?- phrase(nounseq(cons(n4,n4)),Ph0,Ph).
ERROR: noun/3: Cannot unify _G968 with [war|_G968]: would create an infinite tree
So your program relies on STO-unifications (subject-to-occurs-check unifications) whose outcome is explicitly undefined in
ISO/IEC 13211-1 Subclause 7.3.3 Subject to occurs-check (STO) and not subject to occurs-check (NSTO)
This is rather due to your intention to define the intersection of two non-terminals. Consider the following way to express it:
:- op( 950, xfx, //\\). % ASCII approximation for ∩ - 2229;INTERSECTION
(NT1 //\\ NT2) -->
call(Xs0^Xs^(phrase(NT1,Xs0,Xs),phrase(NT2,Xs0,Xs))).
% The following is predefined in library(lambda):
^(V0, Goal, V0, V) :-
call(Goal,V).
^(V, Goal, V) :-
call(Goal).
Already with this definition we can get into STO situations:
?- phrase(([a]//\\[a,b]), Ph0,Ph).
ERROR: =/2: Cannot unify _G3449 with [b|_G3449]: would create an infinite tree
In fact, when using rational trees we get:
?- set_prolog_flag(occurs_check,false).
true.
?- phrase(([a]//\\[a,b]), Ph0,Ph).
Ph0 = [a|_S1], % where
_S1 = [b|_S1],
Ph = [b|_S1].
So there is an infinite list which certainly has not much meaning for natural language sentences (except for persons of infinite resource and capacity...).
I try to check the correctness of student mathematical expression using Prolog (SWI-Prolog). So, for example if the student were asked to add three variable x, y, and z, and there's a rule that the first two variable that must be added are: x and y (in any order), and the last variable that must be added is z then I expect that prolog can give me true value if the student's answer is any of these:
x+y+z
(x+y)+ z
z+(x+y)
z+x+y
y+x+z
and many other possibilities.
I use the following rule for this checking:
addData :-
assert(variable(v1)),
assert(variable(v2)),
assert(variable(v3)),
assert(varName(v1,x)),
assert(varName(v2,y)),
assert(varName(v3,z)),
assert(varExpr(v1,x)),
assert(varExpr(v2,y)),
assert(varExpr(v3,z)).
add(A,B,R) :- R = A + B.
removeAll :- retractall(variable(X)),
retractall(varName(X,_)),
retractall(varExpr(X,_)).
checkExpr :-
% The first two variable must be x and y, in any combination
( (varExpr(v1,AExpr), varExpr(v2,BExpr));
(varExpr(v2,AExpr), varExpr(v1,BExpr))
),
add(AExpr, BExpr, R1),
% store the expression result as another variable, say v4
retractall(variable(v4)),
retractall(varName(v4, _)),
retractall(varExpr(v4, _)),
assert(variable(v4)),
assert(varName(v4, result)),
assert(varExpr(v4, R1)),
% add the result from prev addition with Z (in any combination)
( (varExpr(v3,CExpr), varExpr(v4,DExpr));
(varExpr(v4,CExpr), varExpr(v3,DExpr))
),
add(CExpr, DExpr, R2),
R2 = z + x + y. % will give me false
% R2 = z + (x + y). % will give me true
% Expected: both should give me true
checkCorrect :- removeAll,
addData,
checkExpr.
You should try to specify a grammar and write a parser for your expressions.
Avoid assert/retract, that make the program much more difficult to understand, and attempt instead to master the declarative model of Prolog.
Expressions are recursive data structures, using operators with known precedence and associativity to compose, and parenthesis to change specified precedence where required.
See this answer for a parser and evaluator, that accepts input from text. In your question you show expressions from code. Then you are using Prolog' parser to do the dirty work, and can simply express your requirements on the resulting syntax tree:
expression(A + B) :-
expression(A),
expression(B).
expression(A * B) :-
expression(A),
expression(B).
expression(V) :-
memberchk(V, [x,y,z]).
?- expression(x+y+(x+z*y)).
true .
edit: we can provide a template of what we want and let Prolog work out the details by means of unification:
% enumerate acceptable expressions
checkExpr(E) :-
member(E, [F = A + D, F = D + A]),
F = f,
A = c * N,
N = 1.8,
D = d.
And so on...
Test:
?- checkExpr(f=(c*1.8)+d).
true.
?- checkExpr(f=(c*1.8)+e).
false.
?- checkExpr(f=d+c*1.8).
true.
not(A()) and not(D()) and not(B()) and not(A()).
What's the right way?
The concept of logical negation is already included in Prolog in means of failure. If your implementation doesn't supply it (it can happens) you can think not as
not(P) :- call(P), !, fail.
or
not(P) :- (call(P) -> fail ; true)
Then look at the formula, it can be simplified to have not applied just to single predicates:
~(A & ~D) & ~B & ~A = (~A | D) & ~B & ~A = ~A & ~B
It's just a De Morgan law and a consideration about the fact that D isn't useful to satisfability of the predicate.
then you can combine them:
final_predicate :- not(B), not(A).
EDIT: remember , is AND and ; is OR.
If simply trying to evaluate a propositional logic statement using PROLOG, you could try the following. Start with an encoding of the values of your 'propositions' a, b and d, such as:
a :- true. % this means that a is true.
b :- fail. % this means that b is false
...etc. For example, assuming your statements were:
a :- fail.
b :- fail.
d :- fail.
Then, executing your statement:
?- not(a), not(b), not(d), not(a).
true.
n.b.: The 'propositions' encoded here are 'simulated' - they're actually zero arity first-order predicates as far as PROLOG is concerned.
ps. a :- true. can be simplified to a..
pps. If I'm way off the mark and you're after a way of symbolically manipulating the statement into some other form, such as a normalization, then you need to write what is called a meta-interpreter in PROLOG. Refer to Clocksin and Mellish's Programming in Prolog, Appendix B, 'Clausal Form Program Listings', which might help you.