predsort/3 unexpected behavior - sorting

I have a problem sorting a list of tasks [t7, t1, t6, t2, t4, t3, t5] in Prolog. To sort this I want to use the predefined formula predsort/3 as it seems like the correct approach.
My custom predicate looks like this:
sort_dependency(<, T, T2) :-
depends_on(T,T2,_).
sort_dependency(>, T, T2) :-
depends_on(T2,T,_).
sort_dependency(>, T, T2) :-
T == T2;
not(depends_on(T,T2,_)),
not(depends_on(T2,T,_)).
When testing this I get the following:
?- predsort(sort_dependency, [t7, t1, t6, t2, t4, t3, t5], Sorted).
Sorted = [t5, t4, t3, t7, t2, t6, t1] .
This isn't correct. The correct answer should be something like [t1 , t2, t3, t4, t5, t6, t].
For testing purpose here are the facts of depends_on.
depends_on(t7,t2,0).
depends_on(t7,t6,0).
depends_on(t6,t4,0).
depends_on(t6,t5,0).
depends_on(t2,t1,0).
depends_on(t4,t3,0).
depends_on(t3,t1,0).
depends_on(t5,t3,0).
I tried switching different variables around be still can't get the expected result. Is keysort/2 a better option? Problem is I don't see how to implement keysort in combination with a custom predicate.

Topological sorting is what you actually want. There is top_sort/2 for this.
predsort/3 assumes a total order, but you can only provide a partial order.
In other words, predsort/3 will query your supplied comparison predicate. And it expects as answers <, = or >. So you have to produce one exact answers for all pairs of nodes. However, for some, (those that are incomparable) you cannot tell what the result should be. You can only guess, which will not produce a consistent total order.

I implemented the solution proposed by #false. The tasks are transformed to a graph, edges are set using depends_on and then we use top_sort/2 on the result.
Hope this is useful to some.
sort_tasks(ToSort, Sorted) :-
vertices_edges_to_ugraph(ToSort,[],Gr), %Gr is graph wiht nodes as the tasks
add_my_edges(Gr, ToSort, GrN),
top_sort(GrN,Sorted).
add_my_edges(Gr,[],Gr).
add_my_edges(Gr,[T|TR], GrReturn) :-
findall(X,depends_on(X,T,_),L), %L moet na T gebeuren
add_my_edge(Gr, T, L, GrN),
add_my_edges(GrN,TR,GrReturn).
add_my_edge(Gr, _,[], Gr).
add_my_edge(Gr, T, [LH|LR], GrReturn) :-
add_edges(Gr, [T-LH], GrN),
add_my_edge(GrN, T, LR, GrReturn).

Related

finding a cycle path in prolog

atom_elements(h1,hydrogen,[c1]).
atom_elements(n1,nitrogen,[o1, o2, c2]).
atom_elements(o1,oxygen,[n1]).
atom_elements(o2,oxygen,[n1]).
atom_elements(n2,nitrogen,[o3, o4, c4]).
atom_elements(o3,oxygen,[n2]).
atom_elements(o4,oxygen,[n2]).
atom_elements(h5,hydrogen,[c5]).
atom_elements(n3,nitrogen,[o5, o6, c6]).
atom_elements(o5,oxygen,[n3]).
atom_elements(o6,oxygen,[n3]).
atom_elements(h7,hydrogen,[c7]).
atom_elements(h8,hydrogen,[c7]).
atom_elements(h9,hydrogen,[c7]).
atom_elements(c1,carbon,[c2,c6,h1]).
atom_elements(c2,carbon,[c1,c3,n1]).
atom_elements(c3,carbon,[c2,c7,c4]).
atom_elements(c4,carbon,[c3,c5,n2]).
atom_elements(c5,carbon,[c4,c6,h5]).
atom_elements(c6,carbon,[c1,c5,n3]).
atom_elements(c7,carbon,[c3,h7,h8,h9]).
Example query on the 2,4,6-Trinitrotoluene:
?- tnt(X).
X = [[c1, [c2, n1, o1, o2], c3, [c4, n2, o3, o4], c5,
[c6, n3, o5, o6]]] .
My first step is to find a cycle path and show as a List. But the result is shown as fault. It cannot save the path as a list.
atom_elements(h1,hydrogen,[c1]).
atom_elements(n1,nitrogen,[o1, o2, c2]).
atom_elements(o1,oxygen,[n1]).
atom_elements(o2,oxygen,[n1]).
atom_elements(n2,nitrogen,[o3, o4, c4]).
atom_elements(o3,oxygen,[n2]).
atom_elements(o4,oxygen,[n2]).
atom_elements(h5,hydrogen,[c5]).
atom_elements(n3,nitrogen,[o5, o6, c6]).
atom_elements(o5,oxygen,[n3]).
atom_elements(o6,oxygen,[n3]).
atom_elements(h7,hydrogen,[c7]).
atom_elements(h8,hydrogen,[c7]).
atom_elements(h9,hydrogen,[c7]).
atom_elements(c1,carbon,[c2,c6,h1]).
atom_elements(c2,carbon,[c1,c3,n1]).
atom_elements(c3,carbon,[c2,c7,c4]).
atom_elements(c4,carbon,[c3,c5,n2]).
atom_elements(c5,carbon,[c4,c6,h5]).
atom_elements(c6,carbon,[c1,c5,n3]).
atom_elements(c7,carbon,[c3,h7,h8,h9]).
removeprevious(X,Y):-
X=Y.
filterList(A,In,Out) :-
exclude(removeprevious(A),In,Out).
nextlist(P,C,O) :-
atom_elements(C,_,L),
filterList(P,L,O).
findTNT(Start,Output):-
atom_elements(Start,_,List),
findTNT(Start,Start,List,[],Output).
findTNT(_,_,[],_,[]).
findTNT(Start,_,[H|_],_,Output) :-
H = Start,
write('Find it'), %For debugging%
append([H],[],Output).
findTNT(Start,Privious,[H|T],Visited,Output) :-
write(H+'--'), %For debugging%
H \== Start,
\+ member(H,Visited),
nextlist(Privious,H,List),
append([H],Visited,V),
(
findTNT(Start,H,List,V,Output),
Output = [],
findTNT(Start,Privious,T,V,Output);
append([H],Output,O),
Output is O).
The result is :
The error message is not very good, but it indicates that the problem is with your use of is. Concretely, line 65 of your code reads:
Output is O
At the problematic point in the program, Output is [] and O is [c6], which is why this goal is printed as
[] is [c6]
So the problem is that you are using is on something that is not an arithmetic expression. is is only usable for evaluating arithmetic, for example:
X is 2 + 2
It is not usable for equality of terms. Use = for that. So this last line should maybe be something more like:
Output = O
Except that that will also not work, because you are trying to "assign" a new term to a variable that is already bound to a different term. And you're trying to do "recursive append", which is something that is pretty much always wrong in Prolog. Some recent questions about this: Prolog - Recursively append numbers to a list, Prolog - Recursive append to list returning false

How to access rule data in PROLOG

I have to determine whether two rectangles overlap or not, I can do this but I am struggling with figuring out how to grab my given data, and compare it to eachother to determine larger values.
%This is :what would be happening :
%separate(rectangle(0,10,10,0), rectangle(4,6,6,4))
separate(R1,R2) :-
%I Have to figure out how to take the values from R1 and R2 and compare
%them to one another.
.
It is called "pattern matching".
separated(R1, R2) :-
R1 = rectangle(A1, B1, C1, D1),
R2 = rectangle(A2, B2, C2, D2),
/* now just use your As and Bs */
and in many cases it is better to write straight away:
separated(rectangle(A1, B1, C1, D1), rectangle(A2, B2, C2, D2)) :-
/* now just use your As and Bs */

Prolog Domino Solution

I need an algorithm that given a set of domino pieces, returns every possible end to the game.
I have already found this one, Prolog domino game, but it only adds pieces to the beggining of the set, so it doesn't give you every possible solution.
I replaced this [5-4, 4-3, 3-2, 2-1], with this [[5,4], [4,3], [3,2], [2,1]], and tried adding this line domino_order(In, X, [Out|[X,Y]]) :- select(Piece, In, Remaining), swap_or_not(Piece, [X,Y]), domino_order(Remaining, Y, Out)., but it doesn't work.
writing down the detailed logic would lead to somewhat complex code.
I suggest instead to have a quick check for validity, and let Prolog work out the insertion points.
domino :-
Spare = [4-7,3-4], Curr = [1-2,2-3],
domino_row_add_spare(Curr, Spare, R),
writeln(R).
domino_row_add_spare(C, [], C).
domino_row_add_spare(C, Sps, U) :-
append(L, R, C),
select(X-Y, Sps, Rest),
(append(L, [X-Y|R], C1) ; append(L, [Y-X|R], C1)),
valid(C1),
domino_row_add_spare(C1, Rest, U).
valid([_]).
valid([_-X,X-Y|R]) :- valid([X-Y|R]).

Similarity between trees according to the number of common subtrees in Prolog

I am studying Prolog for an universitary exame using SWI Prolog and I have some problems to understand what my teacher do in this example (it seems to me that is is incomplete) that implement the predicate:
k(T1,T2,N)
that is TRUE if T1 and T2 are trees and if they have if they have exactly N subtrees in common (a subtree is common between two trees T1 and T2 if this subtree exist both in T1 and in T2)
He give me another predicate T(t) where t is a specific tree and T(t) give me all the subtrees of t (if you want to see a graphical interpretation of this thing you can see the slide 18 of this file: http://www.informatica.uniroma2.it/upload/2012/LPDA/08_Lezione_ZNZ.pptx )
So he say that:
k(T1,T2,N)
is TRUE if is TRUE that:
In practice it is TRUE that the trees T1 and T2 have N common subtrees if it is TRUE that the intersection of the subtrees of T1 (give from the T(T1) predicate) and all subtress of T2 (give from the T(T2) predicate) is precisely N in module (ie as a number)
Ok, so go on: he define the trees in the following way:
tree(F, LIST_OF_SUBTREES).
where R is the root of the current tree
So go to implement the predicate k(T1,T2,N) that is TRUE if the trees T1 and T2 have N common subtrees, using the previous property.
This predicate have to use an EXAUSTIVE SEARCH of the subtrees in the trees T1 and T2
Then he implement the k/3 predicate in this way:
k(T1,T2,N) :- t(T1, ST1),
t(T2, ST2),
intersect(ST1,ST2,LST),
lenght(LST,N).
This seems to me pretty clear (correct me if I'm wrong):
t(T1,ST1) put in ST1 the list of all the subtrees contained in T1
t(T2,ST2) put in ST2 the list of all the subtrees contained in T2
intersect(ST1,ST2,LST) put in LST the list of the commons subtrees of ST1 and ST2
lenght(LST,N) put in N the lenght of the commons subtrees of ST1 and ST2
So the predicate k(T1,T2,N) it is true if the calculated value of N unifies with the given N value.
Untill here I think that all is clear...bu now I have some problems to understand how he implement the **t(T,STL) predicate that take a tree T and put in STL the list of all its subtrees.
He give me the following code:
t(T,STL) :- bagof(ST, st(T,ST), STL).
st_r(tree(A,_), tree(A,[]).
st_r(tree(A,R), tree(A,R1) :- st_l(R,R1).
st_l([],[]).
st_l([X|R],[X1|R1]) :- st(X,X1),
st_l(R,R1).
st(T,T1) :- st_r(T,T1).
st(tree(A,R),T1) :- member(T,R),
st(T,T1).
Regarding the predicate:
t(T,STL) :- bagof(ST, st(T,ST), STL).
I think that simply execute the bagof built in predicate where ST is the subtree object that, if satisfy the goal st(T,ST) is put into the STL list (the list of subtree)
But now I am not understanding how the st/2 predicate (my goal) work !!! Someone can try to explain me the logic of this predicate and of the related st_l/2 and st_r/2 predicates?
And please, I have also some doubts about how to concretely build two trees that I can use to test this program. Can you give me two simple trees to use for the testing?
At last I think that, in this example, missing the intersect/3 predicate
Tnx
Andrea
Here the naming it's a bit cryptic, and I'll try to guess it.
st/2 should stand for subtree, its purpose is to enumerate, on backtracking, all subtrees.
st_r/2 should stand for subtree_root. It separately return the root and the leafs.
st_l/2 then should stand for subtree_leafs. It makes a list of 'flattened' trees, replacing actual subtrees.
I would disagree that st/2 enumerates only subtrees. Actually, it returns more trees, because of the pruning performed by the first clause st_r. This seems an unusual definition to me - but nevertheless, it's a definition.
The predicate intersect/3 is defined in SWI-prolog library(lists) as intersection/3.
After two typo correction, that code gives to me
?- t(tree(x,[tree(u,[]),tree(v,[tree(p,[]),tree(q,[])])]),L).
L = [tree(x, []), tree(x, [tree(u, []), tree(v, [])]), tree(x, [tree(u, []), tree(v, [tree(p, []), tree(..., ...)])]), tree(x, [tree(u, []), tree(v, [tree(..., ...)|...])]), tree(x, [tree(u, []), tree(v, [...|...])]), tree(x, [tree(u, []), tree(..., ...)]), tree(x, [tree(..., ...)|...]), tree(x, [...|...]), tree(..., ...)|...].

Find All Relatives with Prolog

I'm having trouble wrapping my head around how I would return a list of everyone related to a certain person. So, if I say relatives(A,B), A would be a person and B is a list of all of the people related to that person. I can write any additional rules needed to assist in doing this. Here is what I have so far.
man(joe).
man(tim).
man(milan).
man(matt).
man(eugene).
woman(mary).
woman(emily).
woman(lily).
woman(rosie).
woman(chris).
parent(milan, mary).
parent(tim, milan).
parent(mary, lily).
parent(mary, joe).
parent(mary, matt).
parent(chris, rosie).
parent(eugene, mary).
parent(eugene, chris).
cousins(A, B) :- parent(C, A), parent(D, B), parent(E, C), parent(E, D), not(parent(C, B)), not(parent(D, A)), A \=B.
paternalgrandfather(A, C) :- man(A), man(B), parent(B, C), parent(A, B).
sibling(A, B) :- parent(C, A), parent(C, B), A \= B.
Can someone guide me as to how I would go about doing this? Thanks.
I think that you should concentrate on the 'true' relation, i.e. parent(Old,Jung), other predicates are irrelevant here. The obvious assumption it's that atoms occurring in parent/2 are identifiers (i.e. names are unique). From this picture seems that all persons here are relatives:
Then your problem should be equivalent to find all connected vertices in parent relation. You can implement a depth first visit, passing down the list of visited nodes to avoid loops (note that you need to go back to parents and down to children!), something like
relatives(Person, Relatives) :-
relatives([], Person, [Person|Relatives]).
relatives(Visited, Person, [Person|Relatives]) :-
findall(Relative, immediate(Person, Visited, R), Immediates),
... find relatives of immediates and append all in relatives.
immediate(Person, Visited, R) :-
(parent(Person, R) ; parent(R, Person)),
\+ member(R, Visited).
See if you can complete this snippet. Note the order of arguments in relatives/3 is choosen to easy maplist/3.
If you are willing to study more advanced code, SWI-Prolog library(ugraph) offers a reachable(+Vertex, +Graph, -Vertices) predicate that does it on a list based graph representation.
Here the SWI-Prolog snippet to get the image (a file to be feed to dot):
graph(Fact2) :-
format('digraph ~s {~n', [Fact2]),
forall(call(Fact2, From, To), format(' ~s -> ~s;~n', [From, To])),
format('}\n').
you can call in this way:
?- tell('/tmp/parent.gv'),graph(parent),told.
and then issue on command line dot -Tjpg /tmp/parent.gv | display
I think you should use builtin predicate findall/3 and maybe sort/2 to avoid duplicates
It would go along these lines:
relatives(Person, Relatives):-
findall(Relative, is_relative(Person, Relative), LRelatives),
sort(LRelatives, Relatives).
is_relative(Person, Relative):-
(cousins(Person, Relative) ; paternalgrandfather(Person, Relative) ; sibling(Person, Relative)).
You might want to add more clauses to is_relative to get more relationships.

Resources