Related
I'm trying to return true if either of the two rules on opposite sides of an or operator succeed in Prolog. It only works if what's on the left side of the or operator is found to be true.
It seems like my code should work according to http://www.cse.unsw.edu.au/~billw/dictionaries/prolog/or.html.
Case2 works when case1 is commented out, so it should be returning true, but because it is on the right side of the operator, it isn't. (?)
For clarity, the parameters mean Person1, Person2, TypeOfCousinsTheyAre, DegreesRemovedTheyAre. I am trying to write rules that determine whether two people are first-cousins-once-removed.
Here is the line that uses the or operator which won't return true if the right side is true:
cousins(A, B, 1, 1) :- ( cousinsCase1(A, B, 1, 1) ; cousinsCase2(A, B, 1, 1) ).
Other things I have tried:
(1) Omitting the or operator and writing two identical functions, but whenever they are called and the top one fails, my program crashes.
cousins(A, B, 1, 1) :- var(FirstCousin),
cousin(A, FirstCousin, 1, 0),
parent(FirstCousin, B),
A \= B.
cousins(A, B, 1, 1) :- var(P1),
parent(P1, A),
cousin(P1, B, 1, 0),
A \= B,
A \= P1,
B \= P1.
(2) I have also tried an if-statement to call the other function if the first one fails, but it crashes if the first case fails again.
cousins(A, B, 1, 1) :- cousinsCase1(A, B, 1, 1) -> true ; cousinsCase2(A, B, 1, 1)).
Is there a different way to call the other rule if the first one fails?
EDIT
To take the advice given, here is more of the code:
Facts:
parent(gggm, ggm).
parent(ggm, gm).
parent(gm, m).
parent(m, self).
parent(self, d).
parent(d, gd).
parent(gggm, gga).
parent(gga, c12a).
parent(c12a, c21a).
parent(c21a, c3).
parent(ggm, ga)
parent(ga, c11a).
parent(c11a, c2).
parent(gm, a).
parent(a, c1).
parent(m, s).
parent(s, n).
parent(n, gn).
parent(c1, c11b).
parent(c11b, c12b).
parent(c2, c21b).
parent(c21b, c22).
parent(c3, c31).
parent(c31, c32).
Other rules I have written in order to get the above ones to work:
% Sibling Rule
sibling(A, B) :- parent(P, A), parent(P, B), A \= B.
% First-cousin Rule:
cousin(A, B, 1, 0) :- sibling(P1, P2), parent(P1, A), parent(P2, B).
% Second-cousin Rule:
cousin(A, B, 2, 0) :- parent(P1, A),
parent(P2, B),
parent(PP1, P1), % your grandparent
parent(PP2, P2), % your grand-aunt/uncle
sibling(PP1, PP2). % they're siblings
% 3rd-cousin and more Rule
cousin(A, B, M, 0) :- ReducedM = M - 1,
cousin(A, B, ReducedM, 0).
Calls to the above rules: Sidenote: Both calls do work but the problem is getting them both to work without commenting out the other rule:
cousins(self, c11b, 1, 1).
This call corresponds to the first "1st-cousin, once-removed" case and the case returns the correct answer of true if the other case is commented out.
cousins(self, c11a, 1, 1).
This call corresponds to the second "1st-cousin, once-removed" case and the case returns the correct answer of true if the other case is commented out.
This is a comment in an answer because it will not format correctly in a comment.
What most beginners to Prolog don't realize early enough is that Prolog is based on logic (that they realize) and the three basics operators of logic and, or and not are operators in Prolog, namely (, ; \+). It is not realizing those operators for what they really are.
Starting with not which in Prolog use to be not/1 but is now commonly (\+)/1.
?- \+ false.
true.
?- \+ true.
false.
or using the older not/1 which you can use but is like speaking in a Shakespearean play because it is no longer done this way. I am including this here because many older examples still have it in the examples this way.
?- not(true).
false.
?- not(false).
true.
Next is and which in Prolog is ,/2.
The reason many new Prolog users don't see this as logical and is that a , in many other programming languages is seen as a statement separator (Ref) and acting much like a , in an English sentence. The entire problem with understating , in programming is that it is really an operator and is used for so many things that programmers don't even realize that it should almost always be thought of as an operator but with many different meanings, (operator overloading). Also because , is used as a statement separator, the statements are typically put on separate lines and some programmers even think that a comma (,) is just a statement end like a period (.) is a line end in a sentence; that is not the way to think of these single character operators. They are operators and need to be seen and comprehended as such.
So now that you know where and how your ideas that cause you problems are coming from, the next time you see a comma , or a period . in a programming language really take time to think about what it means.
?- true,true.
true.
?- true,false.
false.
?- false,true.
false.
?- false,false.
false.
Finally logical or which in Prolog is ;/2 or in DCGs will appear as |/2. The use of |/2 in DCGs is the same as | in BNF.
?- true;true.
true ;
true.
?- true;false.
true ;
false.
?- false;true.
true.
?- false;false.
false.
The interesting thing to note about the results of using or (;) in Prolog is that it will they will return when true as many times as one of the propositions is true and false only when all of the propositions are false. (Not sure if proposition is the correct word to use here). e.g.
?- false;false;false.
false.
?- false;false;true.
true.
?- true;false;true.
true ;
true.
?- true;true;true.
true ;
true ;
true.
In case you didn't heed my warning about thinking about the operators when you see them, how many of you looked at
?- true,true.
true.
and did not think that would commonly be written in source code as
true,
true.
with the , looking like a statement end. , is not a statement end, it is the logical and operator. So do yourself a favor and be very critical of even a single , as it has a specific meaning in programming.
A reverse way to get this idea across is to use the addition operator (+) like a statement end operator which it is not but to someone new to math could be mistakenly taken to be that as seen in this reformatting of a simple math expression.
A =
1 +
2 +
3
That is not how one is use to seeing a simple math expression, but in the same way how some programmers are looking at the use of the , operator.
Over the years one thing I have seen that divides programmers who easily get this from the programmers who struggle with this all their careers are those that do well in a parsing class easily get this because they have to parse the syntax down to the tokens such as ,, then convert that into the semantics of the language.
For more details see section 1.2. Control on page 23 of this paper.
EDIT
You really need to use test cases. Here are two to get you started.
This is done using SWI-Prolog
:- begin_tests(family_relationship).
sibling_test_case_generator(ggm ,gga ).
sibling_test_case_generator(gga ,ggm ).
sibling_test_case_generator(gm ,ga ).
sibling_test_case_generator(ga ,gm ).
sibling_test_case_generator(m ,a ).
sibling_test_case_generator(a ,m ).
sibling_test_case_generator(self,s ).
sibling_test_case_generator(s ,self).
test(01,[forall(sibling_test_case_generator(Person,Sibling))]) :-
sibling(Person,Sibling).
cousin_1_0_test_case_generator(gm ,c12a).
cousin_1_0_test_case_generator(ga ,c12a).
cousin_1_0_test_case_generator(m ,c11a).
cousin_1_0_test_case_generator(a ,c11a).
cousin_1_0_test_case_generator(self,c1 ).
cousin_1_0_test_case_generator(s ,c1 ).
cousin_1_0_test_case_generator(d ,n ).
cousin_1_0_test_case_generator(c12a,gm ).
cousin_1_0_test_case_generator(c12a,ga ).
cousin_1_0_test_case_generator(c11a,m ).
cousin_1_0_test_case_generator(c11a,a ).
cousin_1_0_test_case_generator(c1 ,self).
cousin_1_0_test_case_generator(c1 ,s ).
cousin_1_0_test_case_generator(n ,d ).
test(02,[nondet,forall(cousin_1_0_test_case_generator(Person,Cousin))]) :-
cousin(Person, Cousin, 1, 0).
:- end_tests(family_relationship).
EDIT
By !Original:J DiVector: Matt Leidholm (LinkTiger) - Own work based on: Cousin tree.png, Public Domain, Link
This is an answer.
Using this code based on what you gave in the question and a few changes as noted below this code works. Since you did not give test cases I am not sure if the answers are what you expect or need.
parent(gggm, ggm).
parent(ggm, gm).
parent(gm, m).
parent(m, self).
parent(self, d).
parent(d, gd).
parent(gggm, gga).
parent(gga, c12a).
parent(c12a, c21a).
parent(c21a, c3).
parent(ggm, ga).
parent(ga, c11a).
parent(c11a, c2).
parent(gm, a).
parent(a, c1).
parent(m, s).
parent(s, n).
parent(n, gn).
parent(c1, c11b).
parent(c11b, c12b).
parent(c2, c21b).
parent(c21b, c22).
parent(c3, c31).
parent(c31, c32).
% Sibling Rule
sibling(A, B) :-
parent(P, A),
parent(P, B),
A \= B.
% First-cousin Rule:
cousin(A, B, 1, 0) :-
sibling(P1, P2),
parent(P1, A),
parent(P2, B).
% Second-cousin Rule:
cousin(A, B, 2, 0) :-
parent(P1, A),
parent(P2, B),
parent(PP1, P1), % your grandparent
parent(PP2, P2), % your grand-aunt/uncle
sibling(PP1, PP2). % they're siblings
% 3rd-cousin and more Rule
cousin(A, B, M, 0) :-
% ReducedM = M - 1,
ReducedM is M - 1,
ReducedM > 0,
cousin(A, B, ReducedM, 0).
cousinsCase1(A, B, 1, 1) :-
% var(FirstCousin),
cousin(A, FirstCousin, 1, 0),
parent(FirstCousin, B),
A \= B.
cousinsCase2(A, B, 1, 1) :-
% var(P1),
parent(P1, A),
cousin(P1, B, 1, 0),
A \= B,
A \= P1,
B \= P1.
cousins(A, B, 1, 1) :-
(
cousinsCase1(A, B, 1, 1)
;
cousinsCase2(A, B, 1, 1)
).
The first change was as Paulo noted and the checks for var/2 were commented out.
The next change was to change = to is.
The third change to stop infinite looping was to add ReducedM > 0,.
This query now runs.
?- cousins(Person,Cousin,1,1).
Person = gm,
Cousin = c21a ;
Person = ga,
Cousin = c21a ;
Person = m,
Cousin = c2 ;
Person = a,
Cousin = c2 ;
Person = self,
Cousin = c11b ;
Person = s,
Cousin = c11b ;
Person = d,
Cousin = gn ;
Person = c12a,
Cousin = m ;
Person = c12a,
Cousin = a ;
Person = c12a,
Cousin = c11a ;
Person = c11a,
Cousin = self ;
Person = c11a,
Cousin = s ;
Person = c11a,
Cousin = c1 ;
Person = c1,
Cousin = d ;
Person = c1,
Cousin = n ;
Person = n,
Cousin = gd ;
Person = m,
Cousin = c12a ;
Person = self,
Cousin = c11a ;
Person = d,
Cousin = c1 ;
Person = gd,
Cousin = n ;
Person = c21a,
Cousin = gm ;
Person = c21a,
Cousin = ga ;
Person = c11a,
Cousin = c12a ;
Person = c2,
Cousin = m ;
Person = c2,
Cousin = a ;
Person = a,
Cousin = c12a ;
Person = c1,
Cousin = c11a ;
Person = s,
Cousin = c11a ;
Person = n,
Cousin = c1 ;
Person = gn,
Cousin = d ;
Person = c11b,
Cousin = self ;
Person = c11b,
Cousin = s ;
false.
counter([],[]).
counter([H|T],[[H,C1]|R]) :- counter(T,[[H,C]|R]),!, C1 is C+1.
counter([H|T],[[H,1]|R]) :- counter(T,R).
What is the effect of the "!" as I'm getting the same output for an input in both the above and below code?
counter([],[]).
counter([H|T],[[H,C1]|R]) :- counter(T,[[H,C]|R]),C1 is C+1.
counter([H|T],[[H,1]|R]) :- counter(T,R).
I'm new to Prolog.
What is the effect of the "!"
The cut prunes the search space. That is, in an otherwise pure and monotonic program, the cut will remove some solutions or answers. As long as those are redundant that's fine. It sounds so innocent and useful, doesn't it? Let's have a look!
And lest I forget, using [E,Nr] to denote pairs is rather unusual, better use a pair E-Nr.
We will now compare counter_cut/2 and counter_sans/2.
| ?- counter_cut([a,a],Xs).
Xs = [[a,2]].
| ?- counter_sans([a,a],Xs).
Xs = [[a, 2]]
; Xs = [[a, 1], [a, 1]]. % <<< surprise !!!
So the cut-version has fewer solutions. Seems the solution counter_cut/2 retained is the right one. In this very particular case. Will it always take the right one? I will try a minimally more general query:
| ?- counter_cut([a,B],Xs).
B = a,
Xs = [[a, 2]].
| ?- counter_sans([a,B],Xs).
B = a,
Xs = [[a, 2]]
; Xs = [[a, 1], [B, 1]].
Again, _sans is chattier, and this time, it is even a bit right-er; for the last answer includes B = b. In other words,
| ?- counter_cut([a,B], Xs), B = b.
fails. % incomplete !
| ?- counter_sans([a,B], Xs), B = b.
B = b,
Xs = [[a,1],[b,1]].
So sometimes the _cut version is better, and sometimes _sans. Or to put more directly: Both are wrong somehow, but the _sans-version at least includes all solutions.
Here is a "purified" version, that simply rewrites the last rule into two different cases: One for the end of the list and the other for a further, different element.
counter_pure([],[]).
counter_pure([H|T],[[H,C1]|R]) :- counter_pure(T,[[H,C]|R]), C1 is C+1.
counter_pure([H],[[H,1]]).
counter_pure([H,D|T],[[H,1]|R]) :- dif(H,D), counter_pure([D|T],R).
From an efficiency viewpoint that is not too famous.
Here is a test case for efficiency for a system with rational tree unification:
?- Es = [e|Es], counter(Es, Dict).
resource_error(stack).
Instead, the implementation should loop smoothly, at least till the end of this universe. Strictly speaking, that query has to produce a resource error, but only after it has counted up to a number much larger than 10^100000000.
Here's my pure and hopefully efficient solution:
counter([X|L], C):- counter(L, X, 1, C).
counter([],X, Cnt, [[X,Cnt]]).
counter([Y|L], X, Cnt, [[X,Cnt]|C]):-
dif(X, Y),
counter(L, Y, 1, C).
counter([X|L],X, Cnt, [[X,XCnt]|C]):-
Cnt1 #= Cnt+1,
Cnt1 #=< XCnt,
counter(L, X, Cnt1, [[X,XCnt]|C]).
Using if_3 as suggested by #false:
counter([X|L], C):- counter(L, X, 1, C).
counter([],X, Cnt, [[X,Cnt]]).
counter([Y|L], X, Cnt, [[X,XCnt]|C]):-
if_(X=Y,
(
Cnt1 #= Cnt+1,
Cnt1 #=< XCnt,
counter(L, X, Cnt1, [[X,XCnt]|C])
),
(
XCnt=Cnt,
counter(L, Y, 1, C)
)
).
The cut operator ! commits to the current derivation path by pruning all choice points. Given some facts
fact(a).
fact(b).
you can compare the answers with and without cut:
?- fact(X).
X = a ;
X = b.
?- fact(X), !.
X = a.
As you can see, the general query now only reports its first success. Still, the query
?- fact(b), !.
true.
succeeds. This means, that cut violates the interpretation of , as logical conjunction:
?- X = b, fact(X), !.
X = b.
?- fact(X), !, X=b.
false.
but from our understanding of conjunction, A ∧ B should hold exactly when B ∧ A holds. So why do this at all?
Efficiency: cuts can be used such that they only change execution properties but not the answers of a predicate. These so called green cuts are for instance described in Richard O'Keefe's Craft of Prolog. As demonstrated above, maintaining correctness of a predicate with cut is much harder than one without, but obviously, correctness should come before efficiency.
It looks as if your problem was green, but I am not 100% sure if there is not a change in the answers.
Negation: logical negation according to the closed world assumption is expressed with cut. You can define neg(X) as:
neg(X) :-
call(X),
!,
false.
neg(_) :-
true.
So if call(X) succeeds, we cut the choice point for the second rule away and derive false. Otherwise, nothing is cut and we derive true. Please be aware that this is not negation in classical logic and that it suffers from the non-logical effects of cut. Suppose you define the predicate land/1 to be one of the continents:
land(africa).
land(america).
land(antarctica).
land(asia).
land(australia).
land(europe).
and then define water as everything not on land:
water(X) :-
neg(land(X)).
then you can correctly obtain:
?- water(pacific).
true.
?- water(africa).
false.
But you can also derive:
?- water(space).
true.
which should not hold. In particular, in classical logic:
land(africa) ∧
land(america) ∧
land(antarctica) ∧
land(asia) ∧
land(australia) ∧
land(europe) → ¬ land(space).
is not valid. Again, you should know well what you are doing if you use negation in Prolog.
Here is my attempt using if_/3:
counter([], []).
counter([H|T], [[H,C]|OutT] ):-
if_(
T=[],
(C = 1,OutT=[]),
(
[H|T] = [H,H1|T2],
if_(
H=H1,
(counter([H1|T2], [[H1,C1]|OutT]), C is C1+1),
(C = 1, counter([H1|T2], OutT))
)
)
).
I implemented function to get sublist of list, for example:
sublist([1,2,4], [1,2,3,4,5,1,2,4,6]).
true
sublist([1,2,4], [1,2,3,4,5,1,2,6]).
false
look at my solution:
my_equals([], _).
my_equals([H1|T1], [H1|T2]) :- my_equals(T1, T2).
sublist([], _).
sublist(L1, [H2|T2]) :- my_equals(L1, [H2|T2]); sublist(L1, T2).
Could you give me another solution ? Maybe there is exists some predefined predicate as my_equals ?
You can unify a sublist using append/3, like this:
sublist(SubList, List):-
append(_, Tail, List),
append(SubList, _, Tail).
The first call to append/3 will split List into two parts (i.e. dismiss the some "leading" items from List.
The second call to append/3 will check whether SubList is itself a sublist of Tail.
As #false's suggests it would be better, at least for ground terms, to exchange goals,
sublist(SubList, List):-
append(SubList, _, Tail),
append(_, Tail, List).
There's also a DCG approach to the problem:
substr(Sub) --> seq(_), seq(Sub), seq(_).
seq([]) --> [].
seq([Next|Rest]) --> [Next], seq(Rest).
Which you would call with:
phrase(substr([1,2,4]), [1,2,3,4,5,1,2,4,6]).
You can define:
sublist(Sub, List) :-
phrase(substr(Sub), List).
So you could call it by, sublist([1,2,4], [1,2,3,4,5,1,2,4,6])..
Per #mat's suggestion:
substr(Sub) --> ..., seq(Sub), ... .
... --> [] | [_], ... .
Yes, you can have a predicate named .... :)
Per suggestions from #repeat and #false, I changed the name from subseq (subsequence) to substr (substring) since the meaning of "subsequence" embraces non-contiguous sequences.
This is an alternative solution to Lurkers, which is slightly faster,
assuming S is much shorter than L in length and thus the phrase/3 DCG
translation time is negligible:
sublist(S, L) :-
phrase((..., S), L, _).
If S=[X1,..,Xn] it will DCG translate this into a match I=[X1,..,Xn|O]
before execution, thus delegating my_equals/2 completely to Prolog
unification. Here is an example run:
?- phrase((..., [a,b]), [a,c,a,b,a,c,a,b,a,c], X).
X = [a, c, a, b, a, c] ;
X = [a, c] ;
false.
Bye
P.S.: Works also for other patterns S than only terminals.
Maybe there is exists some predefined predicate
If your Prolog has append/2 from library(lists):
sublist(S, L) :- append([_,S,_], L).
Another fairly compact definition, available in every (I guess) Prolog out there:
sublist(S, L) :- append(S, _, L).
sublist(S, [_|L]) :- sublist(S, L).
Solution in the original question is valid just, as has been said, remark that "my_equals" can be replaced by "append" and "sublist" loop by another append providing slices of the original list.
However, prolog is (or it was) about artificial intelligence. Any person can answer immediately "no" to this example:
sublist([1,1,1,2], [1,1,1,1,1,1,1,1,1,1] ).
because a person, with simple observation of the list, infers some characteristics of it, like that there are no a "2".
Instead, the proposals are really inefficient on this case. By example, in the area of DNA analysis, where long sequences of only four elements are studied, this kind of algorithms are not applicable.
Some easy changes can be done, with the objective of look first for the most strongest condition. By example:
/* common( X, Y, C, QX, QY ) => X=C+QX, Y=C+QY */
common( [H|S2], [H|L2], [H|C2], DS, DL ) :- !,
common( S2, L2, C2, DS, DL ).
common( S, L, [], S, L ).
sublist( S, L ) :-
sublist( [], S, L ).
sublist( P, Q, L ) :- /* S=P+Q */
writeln( Q ),
length( P, N ),
length( PD, N ), /* PD is P with all unbound */
append( PD, T, L ), /* L=PD+T */
common( Q, T, C, Q2, _DL ), /* S=P+C+Q2; L=PD+C+_DL */
analysis( L, P, PD, C, Q2 ).
analysis( _L, P, P, _C, [] ) :- !. /* found sublist */
analysis( [_|L2], P, _PD, C, [] ) :- !,
sublist( P, C, L2 ).
analysis( [_|L2], P, _PD, C, Q2 ) :-
append( P, C, P2 ),
sublist( P2, Q2, L2 ).
Lets us try it:
?- sublist([1,1,1,2], [1,1,1,1,1,1,1,1,1,1]).
[1,1,1,2]
[2]
[2]
[2]
[2]
[2]
[2]
[2]
[2]
false.
see how "analysis" has decided that is better look for the "2".
Obviously, this is a strongly simplified solution, in a real situation better "analysis" can be done and patterns to find must be more flexible (the proposal is restricted to patterns at the tail of the original S pattern).
I have to define some more constraints for my list.
I want to split my list is separate lists.
Example:
List=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2,0],[4,0]]
I need three Lists which i get from the main list:
[[_,0],[_,0],[_,0]] and [[_,0]] and [[2,0],[4,0]]
SO I always need a group of lists between a term with [X,1].
It would be great if u could give me a tip. Don’t want the solution, only a tip how to solve this.
Jörg
This implementation tries to preserve logical-purity without restricting the list items to be [_,_], like
#false's answer does.
I can see that imposing above restriction does make a lot of sense... still I would like to lift it---and attack the more general problem.
The following is based on if_/3, splitlistIf/3 and reified predicate, marker_truth/2.
marker_truth(M,T) reifies the "marker"-ness of M into the truth value T (true or false).
is_marker([_,1]). % non-reified
marker_truth([_,1],true). % reified: variant #1
marker_truth(Xs,false) :-
dif(Xs,[_,1]).
Easy enough! Let's try splitlistIf/3 and marker_truth/2 together in a query:
?- Ls=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2,0],[4,0]],
splitlistIf(marker_truth,Ls,Pss).
Ls = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0],[4,0]],
Pss = [ [[_A,0],[_B,0],[_C,0]], [[_D,0]], [[2,0],[4,0]]] ? ; % OK
Ls = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0],[4,0]],
Pss = [ [[_A,0],[_B,0],[_C,0]], [[_D,0],[9,1],[2,0],[4,0]]],
prolog:dif([9,1],[_E,1]) ? ; % BAD
%% query aborted (6 other BAD answers omitted)
D'oh!
The second answer shown above is certainly not what we wanted.
Clearly, splitlistIf/3 should have split Ls at that point,
as the goal is_marker([9,1]) succeeds. It didn't. Instead, we got an answer with a frozen dif/2 goal that will never be woken up, because it is waiting for the instantiation of the anonymous variable _E.
Guess who's to blame! The second clause of marker_truth/2:
marker_truth(Xs,false) :- dif(Xs,[_,1]). % BAD
What can we do about it? Use our own inequality predicate that doesn't freeze on a variable which will never be instantiated:
marker_truth(Xs,Truth) :- % variant #2
freeze(Xs, marker_truth__1(Xs,Truth)).
marker_truth__1(Xs,Truth) :-
( Xs = [_|Xs0]
-> freeze(Xs0, marker_truth__2(Xs0,Truth))
; Truth = false
).
marker_truth__2(Xs,Truth) :-
( Xs = [X|Xs0]
-> when((nonvar(X);nonvar(Xs0)), marker_truth__3(X,Xs0,Truth))
; Truth = false
).
marker_truth__3(X,Xs0,Truth) :- % X or Xs0 have become nonvar
( nonvar(X)
-> ( X == 1
-> freeze(Xs0,(Xs0 == [] -> Truth = true ; Truth = false))
; Truth = false
)
; Xs0 == []
-> freeze(X,(X == 1 -> Truth = true ; Truth = false))
; Truth = false
).
All this code, for expressing the safe logical negation of is_marker([_,1])? UGLY!
Let's see if it (at least) helped above query (the one which gave so many useless answers)!
?- Ls=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2,0],[4,0]],
splitlistIf(marker_truth,Ls,Pss).
Ls = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0],[4,0]],
Pss = [[ [_A,0],[_B,0],[_C,0]], [[_D,0]], [[2,0],[4,0]]] ? ;
no
It works! When considering the coding effort required, however, it is clear that either a code generation scheme or a
variant of dif/2 (which shows above behaviour) will have to be devised.
Edit 2015-05-25
Above implementation marker_truth/2 somewhat works, but leaves a lot to be desired. Consider:
?- marker_truth(M,Truth). % most general use
freeze(M, marker_truth__1(M, Truth)).
This answer is not what we would like to get. To see why not, let's look at the answers of a comparable use of integer_truth/2:
?- integer_truth(I,Truth). % most general use
Truth = true, freeze(I, integer(I)) ;
Truth = false, freeze(I, \+integer(I)).
Two answers in the most general case---that's how a reified predicate should behave like!
Let's recode marker_truth/2 accordingly:
marker_truth(Xs,Truth) :- subsumes_term([_,1],Xs), !, Truth = true.
marker_truth(Xs,Truth) :- Xs \= [_,1], !, Truth = false.
marker_truth([_,1],true).
marker_truth(Xs ,false) :- nonMarker__1(Xs).
nonMarker__1(T) :- var(T), !, freeze(T,nonMarker__1(T)).
nonMarker__1(T) :- T = [_|Arg], !, nonMarker__2(Arg).
nonMarker__1(_).
nonMarker__2(T) :- var(T), !, freeze(T,nonMarker__2(T)).
nonMarker__2(T) :- T = [_|_], !, dif(T,[1]).
nonMarker__2(_).
Let's re-run above query with the new implementation of marker_truth/2:
?- marker_truth(M,Truth). % most general use
Truth = true, M = [_A,1] ;
Truth = false, freeze(M, nonMarker__1(M)).
It is not clear what you mean by a "group of lists". In your example you start with [1,1] which fits your criterion of [_,1]. So shouldn't there be an empty list in the beginning? Or maybe you meant that it all starts with such a marker?
And what if there are further markers around?
First you need to define the criterion for a marker element. This for both cases: When it applies and when it does not apply and thus this is an element in between.
marker([_,1]).
nonmarker([_,C]) :-
dif(1, C).
Note that with these predicates we imply that every element has to be [_,_]. You did not state it, but it does make sense.
split(Xs, As, Bs, Cs) :-
phrase(three_seqs(As, Bs, Cs), Xs).
marker -->
[E],
{marker(E)}.
three_seqs(As, Bs, Cs) -->
marker,
all_seq(nonmarker, As),
marker,
all_seq(nonmarker, Bs),
marker,
all_seq(nonmarker, Cs).
For a definition of all_seq//2 see this
In place of marker, one could write all_seq(marker,[_])
You can use a predicate like append/3. For example, to split a list on the first occurence of the atom x in it, you would say:
?- L = [a,b,c,d,x,e,f,g,x,h,i,j], once(append(Before, [x|After], L)).
L = [a, b, c, d, x, e, f, g, x|...],
Before = [a, b, c, d],
After = [e, f, g, x, h, i, j].
As #false has pointed out, putting an extra requirement might change your result, but this is what is nice about using append/3:
"Split the list on x so that the second part starts with h:
?- L = [a,b,c,d,x,e,f,g,x,h,i,j], After = [h|_], append(Before, [x|After], L).
L = [a, b, c, d, x, e, f, g, x|...],
After = [h, i, j],
Before = [a, b, c, d, x, e, f, g].
This is just the tip.
To calculate the hamming distance between two lists of the same length, I use foldl(hamm, A, B, 0, R). with this definition of hamm/4:
hamm(A, A, V, V) :- !.
hamm(A, B, V0, V1) :- A \= B, V1 is V0 + 1.
The cut in the first rule prevents the unnecessary backtracking. The second rule, however, could have been written differently:
hamm2(A, A, V, V) :- !.
hamm2(_, _, V0, V1) :- V1 is V0 + 1.
and hamm2/4 will still be correct together with foldl/5 or for queries where both A and B are ground.
So is there a really good reason to prefer the one over the other? Or is there a reason to keep the rules in that order or switch them around?
I know that the query
hamm(a, B, 0, 1).
is false, while
hamm2(a, B, 0, 1).
is true, but I can't quite decide which one makes more sense . . .
The OP implemented two accumulator-style predicates for calculating the Hamming distance (hamm/4 and hamm2/4), but wasn't sure which one made more sense.
Let's read the query that puzzled the OP: "Is there an X such that distance(a,X) is 1?". Here are the "answers" Prolog gives:
?- hamm(a,X,0,1).
false. % wrong: should succeed conditionally
?- hamm2(a,X,0,1). % wrong: should succeed, but not unconditionally
true.
From a logical perspective, both implementations misbehave in above test. Let's do a few tests for steadfastness:
?- hamm(a,X,0,1),X=a. % right
false.
?- hamm(a,X,0,1),X=b. % wrong: should succeed as distance(a,b) is 1
false.
?- hamm2(a,X,0,1),X=a. % wrong: should fail as distance(a,a) is 0
X = a.
?- hamm2(a,X,0,1),X=b. % right
X = b.
Note that in previous queries hamm/4 rightly fails when hamm2/4 wrongly succeeded, and vice-versa.
So both are half-right/half-wrong, and neither one
is steadfast.
What can be done?
Based on if_/3 and (=)/3 presented by #false in this answer, I implemented the following pure code for predicate hamm3/4:
:- use_module(library(clpfd)).
hamm3(A,B,V0,V) :-
if_(A = B, V0 = V, V #= V0+1).
Now let's repeat above queries using hamm3/4:
?- hamm3(a,X,0,1).
dif(X,a).
?- hamm3(a,X,0,1),X=a.
false.
?- hamm3(a,X,0,1),X=b.
X = b.
It works! Finally, let's ask the most general query to see the entire solution set of hamm3/4:
?- hamm3(A,B,N0,N).
A = B, N0 = N ;
dif(A,B), N0+1 #= N.
You already spotted the differences between those definitions: efficiency apart, you should decide about your requirements. Are you going to accept variables in your data structures? Such programming style introduces some of advanced Prolog features (incomplete data structures).
Anyway, I think the first form is more accurate (not really sure about, I would say steadfast on 4° argument)
?- hamm(a, B, 0, 1).
false.
?- hamm(a, B, 0, 0).
B = a.
while hamm2 is
?- hamm2(a, B, 0, 1).
true.
?- hamm2(a, B, 0, 0).
B = a.