different(Xs, Ys) :-
member(X, Xs),
non_member(X, Ys).
different(Xs, Ys) :-
member(Y, Ys),
non_member(Y, Xs).
While this definition using member/2 and non_member/2 is almost1 perfect from a declarative viewpoint, it produces redundant solutions for certain queries and leaves choice points all around.
What is a definition that improves upon this (in a pure manner probably using if_/3 and (=)/3) such that exactly the same set of solutions is described by different/2 but is determinate at least for ground queries (thus does not leave any useless choice points open) and omits (if possible) any redundant answer?
1
Actually, different([a|nonlist],[]), different([],[b|nonlist]) succeeds. It could equally fail. So a solution that fails for both is fine (maybe even finer).
First try!
The following code is based on the meta-predicates tfilter/3 and tpartition/4, the monotone if-then-else control construct if_/3, the reified unary logical connective not_t/3, and the reified term equality predicate (=)/3:
different([],[_|_]).
different([X|Xs0],Ys0) :-
tpartition(=(X),Ys0,Es,Ys1),
if_(Es=[], true, (tfilter(not_t(=(X)),Xs0,Xs1),different(Xs1,Ys1))).
Sample query:
?- different([A,B],[X,Y]).
A=Y , dif(B,Y), X=Y
; A=X , B=X , dif(X,Y)
; A=X , dif(B,X), dif(B,Y), dif(X,Y)
; A=Y , B=Y , dif(X,Y)
; A=Y , dif(B,X), dif(B,Y), dif(X,Y)
; dif(A,X), dif(A,Y).
Let's observe determinism when working with ground data:
?- different([5,4],[1,2]).
true.
The above approach feels like a step in the right direction... But, as-is, I wouldn't call it perfect.
Here's another try! We utilize the monotone if-then-else control construct if_/3, in combination with the reified list membership predicate memberd_t/3, and first argument indexing to avoid the creation of useless choice-points.
different(Xs,Ys) :-
different_aux(Xs,Ys,Xs,Ys).
different_aux([],[_|_],Xs0,Ys0) :-
different_aux(Ys0,[],Ys0,Xs0). % swap Xs/Ys pair
different_aux([X|Xs],Ys,Xs0,Ys0) :-
if_(memberd_t(X,Ys0),
different_aux(Ys,Xs,Ys0,Xs0), % variant: different_aux(Xs,Ys,Xs0,Ys0)
true).
First, we run a query that we expect to fail:
?- different([1,2,3],[2,3,1]).
false.
The following queries are similar to the failing query given above; each one has a single "different" item x placed at different indices in the first [1,2,3] or the second list [2,3,1]:
?- different([4,2,3],[2,3,1]), different([1,2,3],[4,3,1]),
different([1,4,3],[2,3,1]), different([1,2,3],[2,4,1]),
different([1,2,4],[2,3,1]), different([1,2,3],[2,3,4]).
true. % all subgoals succeed deterministically
OK! Let's run another (quite general) query that I used in my
previous answer:
?- different([A,B],[X,Y]).
A=X , B=X , dif(Y,X)
; A=X , dif(B,X), dif(Y,B)
; A=Y , dif(B,X), dif(Y,X)
; dif(A,X), dif(A,Y).
Compact! A big improvement over what I presented
earlier!
(Much inspired by #repeat's last answer, the names are still too clumsy)
different(Xs, Ys) :-
if_(tnotexists_inlist_t(list_memberd_t(Ys), Xs),
true,
tnotexists_inlist_t(list_memberd_t(Xs), Ys)).
tnotexists_inlist_t(_P_2, [], false).
tnotexists_inlist_t(P_2, [E|Es], T) :-
if_(call(P_2, E),
tnotexists_inlist_t(P_2, Es, T),
T = true).
Back to the roots! This variant is very close to the code given by the OP in the question.
The following is based on if_/3 and memberd_t/3.
different(Xs,Ys) :-
if_(some_absent_t(Xs,Ys),
true,
some_absent_t(Ys,Xs,true)).
some_absent_t([] ,_ ,false).
some_absent_t([X|Xs],Ys,Truth) :-
if_(memberd_t(X,Ys), some_absent_t(Xs,Ys,Truth), Truth=true).
Here is a ground query:
?- different([4,2,3],[2,3,1]), different([1,2,3],[4,3,1]),
different([1,4,3],[2,3,1]), different([1,2,3],[2,4,1]),
different([1,2,4],[2,3,1]), different([1,2,3],[2,3,4]).
true. % all subgoals succeed deterministically
And here's the (more general) query I used in previous answers:
?- different([A,B],[X,Y]).
A=X , B=X , dif(Y,X)
; A=X , dif(B,X), dif(B,Y)
; A=Y , B=Y , dif(Y,X), dif(Y,X)
; A=Y , dif(B,X), dif(B,Y), dif(Y,X)
; dif(A,X), dif(A,Y).
Next contestant to the code beauty pageant!-)
This answer shows a refactored variation of code shown in
a previous answer. It uses reified conjunction and disjunction:
and_(P_1,Q_1) :-
and_t(P_1,Q_1,true).
or_(P_1,Q_1) :-
or_t(P_1,Q_1,true).
and_t(P_1,Q_1,Truth) :-
if_(P_1, call(Q_1,Truth), Truth=false).
or_t(P_1,Q_1,Truth) :-
if_(P_1, Truth=true, call(Q_1,Truth)).
Note the two versions for both "and" and "or"; the ones with suffix _t have an extra argument for the truth value, the ones without the suffix do not and assume that Truth=true should hold.
Based on and_t/3 and on reified term inequality predicate dif/3, we define nonmember_t/3:
nonmember_t(X,Ys,Truth) :-
list_nonmember_t(Ys,X,Truth).
list_nonmember_t([] ,_, true).
list_nonmember_t([Y|Ys],X,Truth) :-
and_t(dif(X,Y), list_nonmember_t(Ys,X), Truth).
Now, let's define some_absent_t/3, different_t/3 and different/2, like so:
some_absent_t([] ,_ ,false).
some_absent_t([X|Xs],Ys,Truth) :-
or_t(nonmember_t(X,Ys), some_absent_t(Xs,Ys), Truth).
different_t(Xs,Ys,Truth) :-
or_t(some_absent_t(Xs,Ys),
some_absent_t(Ys,Xs),
Truth).
different(Xs,Ys) :-
different_t(Xs,Ys,true).
Does it still run?
?- different([A,B],[X,Y]).
A=X , B=X , dif(Y,X)
; A=X , dif(B,X), dif(B,Y)
; A=Y , B=Y , dif(Y,X), dif(Y,X)
; A=Y , dif(B,X), dif(B,Y), dif(Y,X)
; dif(A,X), dif(A,Y). % same result as before
?- different([4,2,3],[2,3,1]), different([1,2,3],[4,3,1]),
different([1,4,3],[2,3,1]), different([1,2,3],[2,4,1]),
different([1,2,4],[2,3,1]), different([1,2,3],[2,3,4]).
true. % same result as before
Looks alright!
All in all, not a huge improvement over existing answers, but IMO somewhat more readable code, and a reified version of different/2 as an added bonus!
Let's take it to the limit---by the help of list_nonmember_t/3, exists_in_t/3, and
or_/2!
some_absent_t(Xs,Ys,Truth) :-
exists_in_t(list_nonmember_t(Ys),Xs,Truth).
different(Xs,Ys) :-
or_(some_absent_t(Xs,Ys),
some_absent_t(Ys,Xs)).
The following bold bounty (+500) was offered not too long ago:
An idiomatic answer is still missing here. For example, or_t/3 should rather be (;)/3. There is more to it.
Challenge accepted! This answer is a follow-up to this previous answer.
We use the reified logical connective (;)/3, which can be defined like this:
';'(P_1,Q_1,T) :- if_(P_1, T=true, call(Q_1,T)).
Next, we define the meta-predicate call_/1. It is useful with reified predicates used in this answer. With its name and semantics, call_/1 follows if_/3, and_/2, and or_/2!
call_(P_1) :- call(P_1,true).
Using (;)/3, call_/1, and some_absent_t/3 we implement different/2:
different(As,Bs) :- call_((some_absent_t(As,Bs) ; some_absent_t(Bs,As))).
Done! That's it.
Let's re-run the queries we used in previous answers!
?- different([5,4],[1,2]).
true.
?- different([1,2,3],[2,3,1]).
false.
?- different([4,2,3],[2,3,1]), different([1,4,3],[2,3,1]), different([1,2,4],[2,3,1]),
different([1,2,3],[4,3,1]), different([1,2,3],[2,4,1]), different([1,2,3],[2,3,4]).
true.
Same queries, same answers... Looks alright to me!
Conerning solutions that use if_, I would say an alternative approach would be to use constructive negation from the beginning. Constructive negation was researched already in the 80's, a pioneer was David Chan, and still pops up from time to time.
Assume we have a Prolog interpreter which has a constructive negation (~)/2. This constructive negation (~)/2 can be used to define a declarative if-then-else as follows, lets call this operator (~->)/2:
(A ~-> B; C) :- (A, B); (~A, C).
If the Prolog interpreter has also embedded implication (=>)/2 besides constructive negation, one could alternatively define a declarative if-then-else as follows, lets call this operator (~=>)/2:
(A ~=> B; C) :- (A => B), (~A => C).
Note the switch from disjunction (;)/2 to conjunction (,)/2. Ask the Binary Decision Diagram (BDD) people why they are logically equivalent. Procedurally there are nuances, but through the backdoor of embedded implication for certain A, the second if-then-else variant will also introduce non-determinancy.
But how would we go about and introduce for example constructive negation in a Prolog interpreter. A straight forward way would be to delegate constructive negation to a constraint solver. If the constraint solver has reified negation this can be done as follows:
~ A :- #\ A.
But there not so many constraint solvers around, that would permit a sensible use for examples such as member/2 etc.. Since often they provide reified negation only for domains such as finite integers, rationals, etc.. But for a predicate such as member/2 we would need reified negation for the Herbrand universe.
Also note that the usual approaches for constructive negation also assume that the ordinary rule implication gets another reading. This means that usually under constructive negation, we could pick the ordinary member/2 definition, and get query results such as:
?- ~ member(X, [a,b,c]).
dif(X, a),
dif(X, b),
dif(X, c).
But again the reified negation will hardly easily work with defined predicates, so that the following query will probably not work:
?- #\ member(X, [a,b,c]).
/* typically won't work */
If the above succeeds than any of the declarative if-then-else such as (~->)/2 or (~=>)/2 will have less frequent use, since ordinary predicate definitions will already deliver declarative interpretation by the Prolog interpreter. But why is constructive negation not wide spread? One reason might be the large design space of such a Prolog interpreter. I noticed that we would have the following options:
Backward Chaining: We would basically spit the vanilla interpreter solve/1 into two predicates solvep/1 and solven/1. solvep/1 is responsible for solving positive goals and solven/1 is responsible for solving negative goals. When we try this we will sooner or later see that we need more careful treatment of quantifiers and probably end up with a quantifier elimination method for the Herbrand domain.
Forward Chaining: We will also notice that in backward chaining we will run into problems for the modelling of clauses with disjunction or existential quantifier in the head. This has to do with the fact that the sequent calculus suitable for Prolog has only one formula on the right hand side. So either we go multi formula on the right hand side and will loose paraconsistency, or we use forward chaining.
Magic Sets: But forward chaining will polute the solution spaces in an uncontrolled way. So we might need some form of combination of forward and backward chaining. I don't mean by that only, that we should be able dynamically switch between the two during the solution process, but I mean that we nead also a means to generate sets that direct the forward chaining process.
More problems are also noted in this answer here. This doesn't mean that sooner or later a formula will be found, to fit all this problem and solution pairs together, but it might take some more time.
Bye
Related
I want a predicate to tell whether a particular atom (say x) appears inside a compound term, however deeply nested.
I tried to read about predicates given at https://www.swi-prolog.org/pldoc/man?section=manipterm. I think it will involve walking down the compound term using functor/3 and ../2 recusively. Is there a simpler approach, or some library that does this?
Carlo's elegant answer works on SWI-Prolog but is not portable as the ISO Prolog standard specification for the arg/3 predicate (which most Prolog systems implement) requires its first argument to be bound to an integer, preventing using it as a backtracable generator of compound term arguments. A more portable alternative would be:
haystack_needle(H, N) :-
H == N.
haystack_needle(H, N) :-
functor(H, _, A),
between(1, A, I),
arg(I, H, A),
haystack_needle(A, N).
The between/3 predicate is not specified in the ISO Prolog standard but it's a de facto standard predicate usually provided as either a built-in predicate or a library predicate.
Ignoring cyclic terms, I would use ==/2,compound/1 and arg/3
haystack_needle(H,N) :- H==N.
haystack_needle(H,N) :- compound(H),arg(_,H,A),haystack_needle(A,N).
haystack_needle/2 will succeed multiple times, then will allow for counting occurrences:
?- aggregate(count, haystack_needle(t(a,x,b,[x,x,x]),x), C).
C = 4.
Note, the needle does not need to be an atom...
You can use once/1 to tell if needle appears in haystack:
?- once(haystack_needle(t(a,x,b,[x,x,x]),x)).
true.
?- once(haystack_needle(t(a,x,b,[x,x,x]),z)).
false.
As noted by Paulo, arg/3 could not act appropriately in ISO compliant Prologs.
A portable alternative (with arguments swapped without other purpose than avoiding confusion) could be
needle_haystack(N,H) :- N==H.
needle_haystack(N,H) :- H=..[_|As],member(A,As),needle_haystack(N,A).
Of course, if member/2 is available :)
How to implement rule1 that succeeds iff rule2 returns two or more results?
rule1(X) :-
rule2(X, _).
How can I count the results, and then set a minimum for when to succeed?
How can I count the results, and then set a minimum for when it's true?
It is not clear what you mean by results. So I will make some guesses. A result might be:
A solution. For example, the goal member(X,[1,2,1]) has two solutions. Not three. In this case consider using either setof/3 or a similar predicate. In any case, you should first understand setof/3 before addressing the problem you have.
An answer. The goal member(X,[1,2,1]) has three answers. The goal member(X,[Y,Z]) has two answers, but infinitely many solutions.
So if you want to ensure that there are at least a certain number of answers, define:
at_least(Goal, N) :-
\+ \+ call_nth(Goal, N).
with call_nth/2 defined in another SO-answer.
Note that the other SO-answers are not correct: They either do not terminate or produce unexpected instantiations.
you can use library(aggregate) to count solutions
:- use_module(library(aggregate)).
% it's useful to declare this for modularization
:- meta_predicate at_least(0, +).
at_least(Predicate, Minimum) :-
aggregate_all(count, Predicate, N),
N >= Minimum.
example:
?- at_least(member(_,[1,2,3]),3).
true.
?- at_least(member(_,[1,2,3]),4).
false.
edit here is a more efficient way, using SWI-Prolog facilities for global variables
at_least(P, N) :-
nb_setval(at_least, 0),
P,
nb_getval(at_least, C),
S is C + 1,
( S >= N, ! ; nb_setval(at_least, S), fail ).
with this definition, P is called just N times. (I introduce a service predicate m/2 that displays what it returns)
m(X, L) :- member(X, L), writeln(x:X).
?- at_least(m(X,[1,2,3]),2).
x:1
x:2
X = 2.
edit accounting for #false comment, I tried
?- call_nth(m(X,[1,2,3]),2).
x:1
x:2
X = 2 ;
x:3
false.
with call_nth from here.
From the practical point of view, I think nb_setval (vs nb_setarg) suffers the usual tradeoffs between global and local variables. I.e. for some task could be handly to know what's the limit hit to accept the condition. If this is not required, nb_setarg it's more clean.
Bottom line: the better way to do would clearly be using call_nth, with the 'trick' of double negation solving the undue variable instantiation.
I am quite rusty in prolog, but I am not sure why things like this fail:
frack(3).
frack(X) :- frack(X-1).
So, if I evaluate frack(4). from the interactive prompt with the above facts defined, I expect that it should not have to endlessly recurse, since 4-1 = 3. But I get this error in SWI-Prolog:
ERROR: Out of global stack
Try it:
?- 4-1 = 3.
false.
Why? Because 4-1 = -(4, 1), which clearly is not a number but a compound term.
To reason about integers in Prolog, use clpfd constraints, for example (using GNU Prolog or B-Prolog):
| ?- 4-1 #= X.
X = 3
In SWI-Prolog, the graphical tracer may be useful for you to see what happens:
?- gtrace, frack(4).
For more complex debugging, I recommend failure-slice as shown in false's answer.
Here is the reason for this non-termination. Your query does not terminate, because there is a failure-slice of your program that does not terminate:
?- frack(4).
frack(3) :- false.
frack(X) :-
frack(X-1), false.
You can fix this only by modifying something in the visible part. Three SO-answers suggest to use (is)/2. But this will not remove non-termination! In fact, using (is)/2 leads to essentially the same fragment:
?- frack(4).
frack(3) :- false.
frack(X) :-
Y is X - 1,
frack(Y), false.
At least, frack(4) now succeeds, but it will loop on backtracking. You have to change something in the visible part, like some test for X, in order to avoid non-termination. See failure-slice for more.
frack(X) :- frack(X-1).
should be
frack(X) :- Y is X - 1, frack(Y).
The way you wrote it, X-1 expression of the first level unifies with X variable at the next level, never going for the frack(3) fact.
Prolog doesn't do arithmetic unless you use the is operator:
frack(X) :- X1 is X-1, frack(X1).
What is the best way to express a total order relation in Prolog ?
For example, say I have a set of facts
person(tim)
person(ana)
person(jack)
...
and I want to express the following truth about a person's fortune: for each two persons X and Y, if not(X==Y), either X is richer than Y or Y is richer than X.
So my problem is that the richer clause should be capable of instantiating its variables and also to ensure that it is never the case that richer(X, Y) and richer(Y, X) at the same time.
Here is a better example to see what I mean:
person(tim).
person(john).
happier(tim, john).
hates(X, Y) :- person(X), person(Y), richer(Y, X).
hates(X, Y) :- person(X), person(Y), richer(X, Y), happier(Y, X).
Now the answer to the query hates(john, tim) should return true, because if richer satisfies the mentioned property, one of those two hates clauses must be true. In a resolution based inference engine I could assert the fact (richer(X, Y) V richer(Y, X)) and the predicate hates(john, tim) could be proved to be true.
I don't expect to be able to express this the same way in Prolog with the same effect. However, how can I implement this condition so the given example will work ?
Note also that I don't know who is richer: tim or john. I just now that one is richer than the other.
Thank you.
you cannot write in pure Prolog that a predicate should be a total order: that would require higher order logic since you want to declare a property about a predicate.
this is a predicate that checks if a relationship is total order on a finite set:
is_total_order(Foo,Set):-
forall(
(member(X,Set),
member(Y,Set)),
(
XY =.. [Foo,X,Y],
YX =.. [Foo,Y,X],
(call(XY);call(YX)), %checking if the relationship is total
\+ (call(XY),call(YX), X\=Y) %checking if it's an order
)
).
the operator =../2 (univ operator) creates a predicate from a list (ie: X =.. [foo,4,2]. -> X = foo(4,2)) and the predicate call/1 calls another predicate.
As you can see we use meta-predicates that operate on other predicates.
For an total order on infinite sets things get more complicated since we cannot check every single pair as we did before. I dont even think that it can be written since proving that a relationship is a total order isn't something trivial.
Still, this doesnt declare that a predicate is a total order; it just checks if it is.
So I believe your question is the best way to represent the relation between these 3 people. If you don't actually care about their wealth #'s, just their relative order, you could add predicates like this -
is_richer(tim, anna).
is_richer(anna, jack).
and then a predicate to find all people who X is richer than -
richer(X, Z) :-
is_richer(X, Z).
richer(X, Z) :-
is_richer(X, Y),
richer(Y, Z).
If your is_richer predicate contains cycles though (in this example, if you added is_richer(jack, tim)), this could explode. You need to track where you have visited in this tree.
An example run of richer would be:
?- richer(X, Y).
X=tim
Y=anna ;
X=anna
Y=jack ;
X=tim
y=jack ;
no
(This is NOT a coursework question. Just my own personal learning.)
I'm trying to do an exercise in Prolog to delete elements from a list. Here's my code :
deleteall([],X,[]).
deleteall([H|T],X,Result) :-
H==X,
deleteall(T,X,Result).
deleteall([H|T],X,[H|Result]) :- deleteall(T,X,Result).
When I test it, I first get a good answer (ie. with all the Xs removed.) But then the backtracking offers me all the other variants of the list with some or none of the instances of X removed.
Why should this be? Why do cases where H==X ever fall through to the last clause?
When you are using (==)/2 for comparison you would need the opposite in the third rule, i.e. (\==)/2. On the other hand, such a definition is no longer a pure relation. To see this, consider deleteall([X],Y,Zs), X = Y.
For a pure relation we need (=)/2 and dif/2. Many Prologs like SWI, YAP, B, SICStus offer dif/2.
deleteall([],X,[]).
deleteall([H|T],X,Result) :-
H=X,
deleteall(T,X,Result).
deleteall([H|T],X,[H|Result]) :-
dif(H,X),
deleteall(T,X,Result).
Look at the answers for deleteall([X,Y],Z,Xs)!
Edit (after four years):
More efficiently, but in the same pure vein, this can be written using if_/3 and (=)/3:
deleteall([], _X, []).
deleteall([E|Es], X, Ys0) :-
if_( E = X, Ys0 = Ys, Ys0 = [E|Ys] ),
deleteall(Es, X, Ys).
The last clause says that when removing X from a list, the head element may stay (independently of its value). Prolog may use this clause at any time it sees fit, independently of whether the condition in the preceding clause is true or not backtrack into this clause if another clause fails, or if you direct it to do so (e.g. by issuing ; in the top-level to get the next solution). If you add a condition that the head element may not equal X, it should work.
Edit: Removed the incorrect assertion I originally opened with.