Prolog sum distance between list of nodes ids - prolog

node(1,22,44).
node(2,43,53).
node(3,23,12).
distance(Id1,Id2,D) :-
node(Id1,X1,Y1),
node(Id2,X2,Y2),
D is sqrt((X2-X1)^2 + (Y2-Y1)^2).
distancePath([X,Y],D) :-
distance(X,Y,D).
distancePath([H,X|T],Distance) :-
distancePath([X|T],Rest),
distance(H,X,D),
Aux is Rest + D,
Distance is Distance + Aux.
I have some kind of problem on the distancePath because when i run distancePath([1,2,3],Distance). it give me "Instantiation error in argument 2 of (is)/2" can someone help me?

Distance is Distance + Aux. does not make much sense. Variables are immutable, this means once set the variable will keep the same value in that branch of the Prolog evaluation. Furthermore Distance is unbounded, hence the error.
You actually already have the value for Distance: it is Aux since it is the distance for the Rest of the list, plus the distance D:
distancePath([X,Y], D) :-
distance(X,Y,D).
distancePath([H,X|T], Aug) :-
distancePath([X|T],Rest),
distance(H,X,D),
Aux is Rest + D.
This then gives us:
?- distancePath([1,2,3], D).
D = 68.4652982294199 ;
false.
The above is however not very efficient: it does not make use of tail recursion, and furthermore you perform unpacking of the cons constructor multiple times. You can make use of a helper predicate to boost efficiency:
distancePath([X|T], Result) :-
distancePath(T, X, 0, Result).
distancePath([], _, D, D).
distancePath([J|T], I, Di, Do) :-
distance(I, J, Dd),
D2 is Di + Dd,
distancePath(T, J, D2, Do).

Related

Prolog recursive subtraction

I picked up prolog a couple of days ago and I 'm kind of stuck to this question. I want to subtract a number recursively until that number becomes less than 0. In pseudocode that would be like:
N:=0
while(Y>=X)
{
Y := Y-X
N := N+1
Y := Y+2
}
So for example if I have Y=20 and X=10 then we would get N=2 and Y=4.
Any ideas? Thanks in advance. Any help appreciated. I'm using SWI Prolog.
EDIT 1
What I've accomplished so far is(although I'm not sure even if its correct):
sufficient(X, Y, M, N, F) :-
F is Y-X,
Y>=X,
plus(M, 1, N),
sufficient(X, F, N, N, F).
I have problem finding my base case, I'm confused on how to implement it. Also, in the sufficient I have implemented, obviously when Y<X it terminates returning false. Is there a way to get the N and F before terminating? I am feeling that I am not thinking the "prolog" way, since I am mostly used on C and that vagues my thinking. Thanks.
EDIT 2
I have found my base case and I can stop recursion however, I can't manage to ge the correct values. My code:
sufficient(X, Y, M, N, F) :- Y<X.
sufficient(X, Y, M, N, F) :-
F is Y-X,
plus(M, 1, N),
sufficient(X, F, N, D, E).
Thing is after the first recursion, if for example I call sufficient as sufficient(10,21,0,N,F). from the swi prolog command prompt, I 'll get N=1 and F=11. That happens because I make 2 new variables D and E. If I don't make those 2 new variables(D and E), and at the 3rd sufficient in the code I call N and F instead of D and E at the line F is Y-X, I get a false, because F is 11 and Y-X is 1. Do I have to set the a subtraction function myself, since F is Y-X is not exactly a subtraction? Any ideas on how to do it?
All recursive functions need at least one base case. In what circumstance should your function say, OK, I have the answer, no need to recurse?
It would be the case in which your pseudocode loop is done, right?
Usually we write it in this format:
factorial(0,1). % The factorial of 0 is 1.
factorial(N,Factorial) :-
N>0, % You may need to test applicability
% of this recursive clause
NMinus1 is N-1, % maybe some setup
factorial(NMinus1,FactorialOfNMinus1), %recursive call
Factorial is N*FactorialOfNMinus1). %and maybe some code after
I wouldn't want to do your homework for you, but this should get you going:
sufficient(X,Y,M,N,F) :- %whatever condition means you're done,
% and results = whatever they should
sufficient(X,Y,M,N,F) :- %whatever condition means you aren't done
% and setting up results w/ a recursive call
One more hint: looks like M is a temporary variable and need not be a parameter.

Prolog: How to calculate depth of tree with an arbitrary amount of subtrees?

I represent trees with an arbitrary, but finite, amount of subtrees like this:
tree(empty).
tree(branch(R, Ts)) :- integer(R), isTreeList(Ts).
isTreeList([]).
isTreeList([T | Ts]) :- tree(T), isTreeList(Ts).
(please ignore if this representation is good or bad, it's just for the purpose of asking this question)
This post shows how calculate the depth of a binary tree. My progress so far:
depth(tree(empty), 0).
depth(tree(branch(_, SubTrees), D)
:- < calculate somehow the depths D1, ..., Dn of the subtrees >
, max_list([D1, ..., Dn], MaxD)
, D is MaxD + 1
How do I determine D1, ..., Dn?
EDIT: According to #CapelliC the following is one solution to the problem:
depth(tree(empty), 0).
depth(tree(branch(_, SubTrees), D)
:- maplist(depth, SubTrees, Depths)
, max_list(Depths, MaxD)
, D is MaxD + 1
Mind that this will fail if SubTrees is the empty list – the solution of #max66 will still work.
You could check the max value everytime you calculate a value in the list.
I mean
depth(tree(empty), 0).
depth([], 0).
depth([T | L], D) :-
depth(T, D0),
depth(L, D1),
D is max(D0, D1).
depth(tree(branch(_, SubTrees)), D) :-
depth(SubTrees, D0),
D is D0+1.

Dcg state implementation of algorithm

The distance between a long sequence and a short sequence, is the minimum distance between the short sequence and any subsequence of the long sequence that is the same length as the short sequence.
The distance I am using is I think the Manhattan distance. (But this should be unimportant as I would like to be able to change distance functions).
This first version shows a naive implementation without early abandon. I generate all subsequence of the same length, map these to find the distance between them and the short sequence and then use aggregate/3 to find the min.
abs(X,Y,Z):-
Z is abs(X-Y).
seq_seq_absdis(Seq1,Seq2,Dis):-
same_length(Seq1,Seq2),
maplist(abs,Seq1,Seq2,Dislist),
sumlist(Dislist,Dis).
seq_subseq(List1,List2):-
append(List2,_,List1),
dif(List2,[]).
seq_subseq([_|T],Subseq):-
seq_subseq(T,Subseq).
smallseq_largeseq_dis(Sseq,Lseq,Dis):-
findall(Subseq, (same_length(Subseq,Sseq),seq_subseq(Lseq,Subseq)),Subseqs),
maplist(seq_seq_absdis(Sseq),Subseqs,Distances),
aggregate(min(D),member(D,Distances),Dis).
Example query:
?-smallseq_largeseq_dis([1,2,4],[1,2,3,1,2,5],Dis).
Dis = 1
This next version should be more efficient, as it will abandon calculating the distance between a subsequence of the long sequence and the short sequence once the distance is over the minimum already found.
ea_smallseq_largeseq_dis(Sseq,Lseq,Subseq,Dis):-
retractall(best(_,_)),
assert(best(initial,10000)),
findall(Subseq-Dis, ea_smallseq_largeseq_dis_h(Sseq,Lseq,10000,Subseq,Dis),Pairs),
append(_,[Subseq-Dis|[]],Pairs).
ea_smallseq_largeseq_dis_h(Sseq,Lseq,BestSofar1,Subseq,Dis):-
same_length(Sseq,Subseq),
seq_subseq(Lseq,Subseq),
best(_,BestSofar2),
( ( BestSofar2 < BestSofar1) ->
accumulate_dis(Sseq,Subseq,BestSofar2,Dis),
retractall(best(_,_)),
assert(best(Subseq,Dis))
;(
accumulate_dis(Sseq,Subseq,BestSofar1,Dis),
retractall(best(_,_)),
assert(best(Subseq,Dis))
)
).
accumulate_dis(Seq1,Seq2,Best,Dis):-
accumulate_dis(Seq1,Seq2,Best,Dis,0).
accumulate_dis([],[],_Best,Dis,Dis).
accumulate_dis(Seq1,Seq2,Best,Dis,Ac):-
Seq1=[H1|T1],
Seq2=[H2|T2],
abs(H1,H2,Dis1),
Ac1 is Dis1 + Ac,
Ac1 <Best,
accumulate_dis(T1,T2,Best,Dis,Ac1).
Query:
?-ea_smallseq_largeseq_dis([1,2,3],[1,2,4,5,6,7,8,1,2,3],Subseq,Dis).
Dis = 0,
Subseq = [1, 2, 3]
But in this I have used assert and retract so I want to have a version which does the same algorithm but with out these. I think I should be able to do this with a dcg with semicontext notation but find it hard to grasp... how do I keep track of the subsequences I am generating by backtracking and at the same time the 'state' of the minimum distance found so far?
The problem I have..
seq_subseq/2 is generating the sub-sequences by back tracking.
The first subseq tested needs to be set to the min distance.
I then want to loop, so back track to generate another sequence. But to back track I have to fail. But then I cant bring back the min distance so far to check on the next sequence.
If I don't want to use backtracking, I think I need to define a state transition predicate for generating the sub-sequences in order.
At the moment
? seq_subseq([1,2,3,4],X).
X = [1]
X = [1, 2]
X = [1, 2, 3]
X = [1, 2, 3, 4]
X = [2]
X = [2, 3]
X = [2, 3, 4]
X = [3]
X = [3, 4]
X = [4]
So I think I need to define a relation:
subseq0_seq_subseq1(Subseq0,Seq,Subseq1)
That would work like:
?-subseq0_seq_subseq1([1,2,3,4],[1,2,3,4],Subseq1).
Subseq1 = [2].
and
?-subseq0_seq_subseq1([1,2,3],[1,2,3,4],Subseq1).
Subseq1 = [1,2,3,4].
But I need to do this in an efficient way.
Update- Thanks to the answer from Mat I now have this, which is a great improvement I think. Can anyone see any further improvements to this? I have a double nested -> structure and a ! in the accumulate_dis/4 definition both of which seem ugly. I have also made it return the sub-sequence of the long-sequence which is the shortest distance away from the short sequence.
It needs to work with non integers so clpfd is not appropriate I think.
abs(X,Y,Z):-
Z is abs(X-Y).
list_subseq_min(Ls, Subs, Min,BestSeq1) :-
prefix_dist(Ls, Subs, 1000, Front, D0),
BestSeq0=Front,
min_sublist(Ls, Subs,BestSeq0,BestSeq1, D0, Min).
prefix_dist(Ls, Ps, Best,Front,D) :-
same_length(Front, Ps),
append(Front, _, Ls),
accumulate_dis(Front, Ps, Best, D).
min_sublist(Ls0, Subs, BestSeq0,BestSeq2, D0, D) :-
( prefix_dist(Ls0, Subs, D0, Front,D1) ->
min_list([D0,D1],D2),
Ls0 = [_|Ls],
( D0 < D1 ->
BestSeq1 =BestSeq0
;
BestSeq1 =Front
),
min_sublist(Ls, Subs, BestSeq1,BestSeq2, D2, D)
; D = D0,BestSeq0 =BestSeq2
).
accumulate_dis(Seq1,Seq2,Best,Dis):-
accumulate_dis(Seq1,Seq2,Best,Dis,0),!.
accumulate_dis([],[],_Best,Dis,Dis).
accumulate_dis(Seq1,Seq2,Best,Dis,Ac):-
Seq1=[H1|T1],
Seq2=[H2|T2],
abs(H1,H2,Dis1),
Ac1 is Dis1 + Ac,
Ac1 <Best,
accumulate_dis(T1,T2,Best,Dis,Ac1).
accumulate_dis(Seq1,Seq2,Best,Dis):-Dis is Best+1.
query:
?- list_subseq_min([2.1,3.4,4,1.1,2,4,10,12,15],[1,2,3],D,B).
D = 1.1,
B = [1.1, 2, 4].
One important note: You should have clearified that you are talking about the Manhatten distance between lists. This was only clear from your code, whereas your wording can easily lead readers to assume you are talking about the edit distance.
Here is a solution that simply walks the list, keeps track of the minimum, and eventually yields the found minimum.
list_subseq_min(Ls, Subs, Min) :-
prefix_dist(Ls, Subs, D0),
min_sublist(Ls, Subs, D0, Min).
absdiff(X, Y, Z):- Z #= abs(X-Y).
lists_dist(Ls1, Ls2, D) :-
maplist(absdiff, Ls1, Ls2, Ds),
sum(Ds, #=, D).
prefix_dist(Ls, Ps, D) :-
same_length(Front, Ps),
append(Front, _, Ls),
lists_dist(Front, Ps, D).
min_sublist(Ls0, Subs, D0, D) :-
( prefix_dist(Ls0, Subs, D1) ->
D2 #= min(D0,D1),
Ls0 = [_|Ls],
min_sublist(Ls, Subs, D2, D)
; D #= D0
).
Example query and its result:
?- list_subseq_min([1,2,3,1,2,5], [1,2,4], D).
D = 1.
It's quite straight-forward, and since the bookkeeping is limited to only one predicate, using semicontext notations does not really pay off. It is especially useful to use semicontext notation—and DCGs in general—when what is being described spans different rules and communication between them would otherwise be harder.
The running time is in O(N×M).
And now the point, which I leave as an exercise: Modify this solution to prune earlier, if the previously found minimum is already exceeded. Do so in a pure way, or at least as pure as possible: assertz/1 and friends are definitely out of the question, since they prevent your testing these predicates in isolation. Pass around arguments and build the distance more incrementally! This may help you to improve the average running time, though of course not the worst case complexity.
It is for this passing around states between different clauses that semicontext notation may become useful at last.
EDIT: Very well, you have implemented a solution that does the pruning. I will now also show mine. I will reuse the auxiliary predicates absdiff/3 and lists_dist/3 from above, and the following additional auxiliary predicate:
same_length_prefix(Ls, Ps, Front) :-
same_length(Front, Ps),
append(Front, _, Ls).
list_subseq_min/3 is now slightly different:
list_subseq_min(Ls, Subs, Min) :-
same_length_prefix(Ls, Subs, Front),
lists_dist(Front, Subs, D0),
phrase(min_sublist(Ls, Subs), [D0-Front], [Min-_]).
And now the point: min_sublist//2 is a DCG nonterminal that concisely describes the main idea of the algorithm:
min_sublist(Ls0, Subs) -->
( front(Ls0, Subs) ->
{ Ls0 = [_|Ls] },
min_sublist(Ls, Subs)
; []
).
From this description, it is very clear that we are considering the list element by element. It uses fewer (explicit) arguments than previously. The additional two arguments are implicitly passed around as a pair D-Front, which keeps track of the best distance and subsequence found so far. Note how DCG notation exposes the core of the computation, and hides what is not relevant at this place.
The rest is quite self-explanatory, and is analogous to the pruning you have implemented. I highlight the single use of semicontext notation in this program, which lets us express any change of the optimal sequence found so far.
front(Ls, Subs), [D-Front] -->
[Current],
{ same_length_prefix(Ls, Subs, Front1),
capped_dist(Front1, Subs, Current, 0-Front1, D-Front) }.
capped_dist([], [], _, DF, DF).
capped_dist([L|Ls], [P|Ps], Current, D1-Front1, DF) :-
absdiff(L, P, D2),
D3 #= D1 + D2,
Current = D0-_,
( D3 #> D0 -> DF = Current
; capped_dist(Ls, Ps, Current, D3-Front1, DF)
).
I can't bring myself to accept the nastiness and primitiveness of contemporary floating-point numbers, so I have retained the integer arithmetic and simply multiply all numbers you show so that they become integers:
?- list_subseq_min([21,34,40,11,20,40,100,120,150], [10,20,30], D).
D = 11.
I leave extending this so that it also shows the found subsequence as an easy exercise.
One important note: The capping only affects the calculation of the distance; note in particular that the running time is Θ(N×M) due to the way same_length_prefix/3 is used in front//2! I leave improving this as a slightly harder exercise.

Prolog confusion. Can someone explain how minimal works?

I understand the code up to minimal but after that there's too many variables and I keep losing track of what each one is doing. If someone could explain it or do it with renamed variables that would be an amazing help, as I think this code will probably come up on my Christmas exam and I want to be able to explain what's going on.
road(a, b, 1).
road(b, c, 1).
road(a, c, 13).
road(d, a, 1).
/*Getting from A to B through a list of places R in N kms*/
route(A,B,R,N) :- travel(A,B,[A],Q,N), reverse(Q,R).
/*Travelling from A to B through P a list of towns B|P of distance L*/
travel(A,B,P,[B|P],Dist) :- road(A,B,Dist).
/*Travelling from A to B through Visited, on your Route R with distance Distance*/
/*Find if there is a road from A to b and store the distance. Make sure C is not equal to B*/
travel(A,B,Visited,R,Distance) :-
road(A,C,Dist), C \== B,
/*Make sure C is not in Visited to avoid infinite loop,
use recursion to find the full route and distance */
\+member(C,Visited), travel(C,B,[C|Visited],R,Dist1), Distance is Dist + Dist1.
/*Find the shortest route from A to B*/
shortest(A,B,R,N) :-
setof([Route,Dist],route(A,B,Route,Dist),Set),
Set = [_|_], minimal(Set,[R,N]).
minimal([F|R],M) :- min(R,F,M).
/*The shortest path*/
min([],M,M).
min([[P,L]|R],[_,M],Min):- L < M, !, min(R,[P,L],Min).
min([_|R],M,Min) :- min(R,M,Min).
since setof gives a sorted list of solutions, it's sufficient to produce solutions of appropriate 'shape', placing first the value you want to minimize: try
shortest(A,B,R,N) :-
setof((Dist,Route), route(A,B,Route,Dist), [(N,R)|_]).

How to add polynoms in Prolog?

I have the following task:
Write a method that will add two polynoms. I.e 0+2*x^3 and 0+1*x^3+2*x^4 will give 0+3*x^3+2*x^4.
I also wrote the following code:
add_poly(+A1*x^B1+P1,+A2*x^B2+P2,+A3*x^B3+P3):-
(
B1=B2,
B3 = B2,
A3 is A1+A2,
add_poly(P1,P2,P3)
;
B1<B2,
B3=B1,
A3=A1,
add_poly(P1,+A2*x^B2+P2,P3)
;
B1>B2,
B3=B2,
A3=A2,
add_poly(+A1*x^B1+P1,P2,P3)
).
add_poly(X+P1,Y+P2,Z+P3):-
Z is X+Y,
add_poly(P1,P2,P3).
My problem is that I don't know how to stop. I would like to stop when one the arguments is null and than to append the second argument to the third one. But how can I check that they are null?
Thanks.
Several remarks:
Try to avoid disjunctions (;)/2 in the beginning. They need special indentation to be readable. And they make reading a single rule more complex — think of all the extra (=)/2 goals you have to write and keep track of.
Then, I am not sure what you can assume about your polynomials. Can you assume they are written in canonical form?
And for your program: Consider the head of your first rule:
add_poly(+A1*x^B1+P1,+A2*x^B2+P2,+A3*x^B3+P3):-
I will generalize away some of the arguments:
add_poly(+A1*x^B1+P1,_,_):-
and some of the subterms:
add_poly(+_+_,_,_):-
This corresponds to:
add_poly(+(+(_),_),_,_) :-
Not sure you like this.
So this rule applies only to terms starting with a prefix + followed by an infix +. At least your sample data did not contain a prefix +.
Also, please remark that the +-operator is left associative. That means that 1+2+3+4 associates to the left:
?- write_canonical(1+2+3+4).
+(+(+(1,2),3),4)
So if you have a term 0+3*x^3+2*x^4 the first thing you "see" is _+2*x^4. The terms on the left are nested deeper.
For your actual question (how to stop) - you will have to test explicitly that the leftmost subterm is an integer, use integer/1 - or maybe a term (*)/2 (that depends on your assumptions).
I assume that polynomials you are speaking of are in 1 variable and with integer exponents.
Here a procedure working on normal polynomial form: a polynomial can be represented as a list (a sum) of factors, where the (integer) exponent is implicitly represented by the position.
:- [library(clpfd)].
add_poly(P1, P2, Sum) :-
normalize(P1, N1),
normalize(P2, N2),
append(N1, N2, Nt),
aggregate_all(max(L), (member(M, Nt), length(M, L)), LMax),
maplist(rpad(LMax), Nt, Nn),
clpfd:transpose(Nn, Tn),
maplist(sumlist, Tn, NSum),
denormalize(NSum, Sum).
rpad(LMax, List, ListN) :-
length(List, L),
D is LMax - L,
zeros(D, Z),
append(List, Z, ListN).
% the hardest part is of course normalization: here a draft
normalize(Ts + T, [N|Ns]) :-
normalize_fact(T, N),
normalize(Ts, Ns).
normalize(T, [N]) :-
normalize_fact(T, N).
% build a list with 0s left before position E
normalize_fact(T, Normal) :-
fact_exp(T, F, E),
zeros(E, Zeros),
nth0(E, Normal, F, Zeros).
zeros(E, Zeros) :-
length(Zeros, E),
maplist(copy_term(0), Zeros).
fact_exp(F * x ^ E, F, E).
fact_exp(x ^ E, 1, E).
fact_exp(F * x, F, 1).
fact_exp(F, F, 0).
% TBD...
denormalize(NSum, NSum).
test:
?- add_poly(0+2*x^3, 0+1*x^3+2*x^4, P).
P = [0, 0, 0, 3, 2]
the answer is still in normal form, denormalize/2 should be written...

Resources