I need to find the fastest way to travel from one city to another. I have something like
way(madrid, barcelona, 4).
way(barcelona, paris, 5).
way(madrid, londres, 3).
way(londres,paris,1).
I have come up with a predicate shortway(A,B,C,D) where C is the list of towns between A and B and D the distance.
so I have
shortway(A,B,C,D):-
way(A,B,_,_) , (A,_,C,D). D<C.
shortway(A,_,C).
I trying my best but I really cant get it to work!
You have a bunch of problems with your code! First of all, way/3 has arity 3, not 4, so calling way(A,B,_,_,) is clearly not going to do what you think. Second, I have no idea what you're trying to do with (A,_,C,D). The period after this signifies the end of the predicate! So the next line, D<C. is just a free-floating query that cannot be fulfilled. And then shortway(A,_,C) is basically a fact, with three singletons, but it would define a shortway/3 clause when the previous one is a shortway/4 clause.
There really isn't enough that's on the right track here to try and recover. It looks here like you are extremely confused about even the basics of Prolog. I would strongly encourage you to go back to the beginning and start over. You can't rush Prolog! And this code looks like you're trying to make a combustion engine by banging rocks together.
I wrote some line of code to help you, but as https://stackoverflow.com/users/812818/daniel-lyons said, it's better than you learn something easier before.
To solve your problem I advice you to read, at least, the first 3 chapters of this book: http://www.learnprolognow.org/lpnpage.php?pageid=online and do the practical session at paragraph 3.4.
Then, you could take a look at my code (you can find some explenation of it here:Out of local stack error in Prolog route planner .
Here the code
way(madrid, barcelona, 4).
way(barcelona, paris, 5).
way(madrid, londres, 3).
way(londres,paris,1).
shortway(From, To):- findall(Journey, travel(From, To, Journey, _) , Travels_list),
findall(Total_distance, travel(From, To, _, Total_distance) , Distances_list),
min_member(Y, Distances_list), find_minimum_index(Y, Distance_list, 1, Distance_index),
find_journey(Distance_index, Travels_list, 0, Shortest_path),
format('The shortest path is ~w', [Shortest_path]).
travel(From, To, Journey, Total_distance) :- dif(From, To),
AccDistance is 0,
path(From, To, [From], Journey, AccDistance, Total_distance).
path(From, To, Passed_cities, go(From, To), AccDistance, Total_distance) :- way(From, To, Way_distance),
Total_distance is AccDistance + Way_distance.
path(From, To, Passed_cities, go(From, Intermediate, GO), AccDistance, Total_distance) :- way(From, Intermediate, Way_distance),
dif(Intermediate, To),
\+ member(Intermediate, Passed_cities),
NewAccDistance is AccDistance + Way_distance,
path(Intermediate, To, [Intermediate|Passed_cities], GO, NewAccDistance, Total_distance).
min_member(Min, [H|T]) :- min_member_(T, H, Min).
min_member_([], Min, Min).
min_member_([H|T], Min0, Min) :-
( H >= Min0
-> min_member_(T, Min0, Min)
; min_member_(T, H, Min)
).
find_minimum_index(X, [], N, I) :- fail.
find_minimum_index(X, [X|T], N, I) :- I is N, !.
find_minimum_index(X, [H|T], N, I) :- H \= X, increment(N, N1), find_minimum_index(X, T, N1, I).
find_journey(I, [H|T], N, Elemento) :- N = I, Elemento = H, !.
find_journey(I, [H|T], N, Elemento) :- N \= I, increment(N, N1), find_journey(I, T, N1, Elemento).
increment(X, X1) :- X1 is X+1.
Then you call, for example
?:- shortway(madrid,paris).
and it will return
"The shortest path is go(madrid, londres, go(londres,paris))"
which distance is, 4
rather than
go(madrid, barcelona, go(barcelona, madrid)
which distance is 9.
Summing up: calling shortway/2, with the predicates findall/3 you'll find the lists of all possible pathes and their relative distances, respectively, then you'll browse the list of the distances to find the index of the minimum element and so using it to find the shortest path from the list of all pathes found previously.
Related
I like the idea of lazy_findall as it helps me with keeping predicates separated and hence program decomposition.
What are the cons of using lazy_findall and are there alternatives?
Below is my "coroutine" version of the branch and bound problem.
It starts with the problem setup:
domain([[a1, a2, a3],
[b1, b2, b3, b4],
[c1, c2]]).
price(a1, 1900).
price(a2, 750).
price(a3, 900).
price(b1, 300).
price(b2, 500).
price(b3, 450).
price(b4, 600).
price(c1, 700).
price(c2, 850).
incompatible(a2, c1).
incompatible(b2, c2).
incompatible(b3, c2).
incompatible(a2, b4).
incompatible(a1, b3).
incompatible(a3, b3).
Derived predicates:
all_compatible(_, []).
all_compatible(X, [Y|_]) :- incompatible(X, Y), !, fail.
all_compatible(X, [_|T]) :- all_compatible(X, T).
list_price(A, Threshold, P) :- list_price(A, Threshold, 0, P).
list_price([], _, P, P).
list_price([H|T], Threshold, P0, P) :-
price(H, P1),
P2 is P0 + P1,
P2 =< Threshold,
list_price(T, Threshold, P2, P).
path([], []).
path([H|T], [I|Q]) :-
member(I, H),
path(T, Q),
all_compatible(I, Q).
The actual logic:
solution([], Paths, Paths, Value, Value).
solution([C|D], Paths0, Paths, Value0, Value) :-
( list_price(C, Value0, V)
-> ( V < Value0
-> solution(D, [C], Paths, V, Value)
; solution(D, [C|Paths0], Paths, Value0, Value)
)
; solution(D, Paths0, Paths, Value0, Value)
).
The glue
solution(Paths, Value) :-
domain(D),
lazy_findall(P, path(D, P), Paths0),
solution(Paths0, [], Paths, 5000, Value).
Here is an alternative no-lazy-findall solution by #gusbro: https://stackoverflow.com/a/68415760/1646086
I am not familiar with lazy_findall but I observe two "drawbacks" with the presented approach:
The code is not as decoupled as one might want, because there is still a mix of "declarative" and "procedural" code in the same predicate. I am putting quotes around the terms because they can mean a lot of things but here I see that path/2 is concerned with both generating paths AND ensuring that they are valid. Similarly solution/5 (or rather list_price/3-4) is concerned with both computing the cost of paths and eliminating too costly ones with respect to some operational bound.
The "bounding" test only happens on complete paths. This means that in practice all paths are generated and verified in order to find the shortest one. It does not matter for such a small problem but might be important for larger instances. Ideally, one might want to detect for instance that the partial path [a1,?,?] will never bring a solution less than 2900 without trying all values for b and c.
My suggestion is to instead use clpfd (or clpz, depending on your system) to solve both issues. With clpfd, one can first state the problem without concern for how to solve it, then call a predefined predicate (like labeling/2) to solve the problem in a (hopefully) clever way.
Here is an example of code that starts from the same "setup" predicates as in the question.
state(Xs,Total):-
domain(Ds),
init_vars(Ds,Xs,Total),
post_comp(Ds,Xs).
init_vars([],[],0).
init_vars([D|Ds],[X|Xs],Total):-
prices(D,P),
length(D,N),
X in 1..N,
element(X, P, C),
Total #= C + Total0,
init_vars(Ds,Xs,Total0).
prices([],[]).
prices([V|Vs],[P|Ps]):-
price(V,P),
prices(Vs,Ps).
post_comp([],[]).
post_comp([D|Ds],[X|Xs]):-
post_comp0(Ds,D,Xs,X),
post_comp(Ds,Xs).
post_comp0([],_,[],_).
post_comp0([D2|Ds],D1,[X2|Xs],X1):-
post_comp1(D1,1,D2,X1,X2),
post_comp0(Ds,D1,Xs,X1).
post_comp1([],_,_,_,_).
post_comp1([V1|Vs1],N,Vs2,X1,X2):-
post_comp2(Vs2,1,V1,N,X2,X1),
N1 is N+1,
post_comp1(Vs1,N1,Vs2,X1,X2).
post_comp2([],_,_,_,_,_).
post_comp2([V2|Vs2],N2,V1,N1,X2,X1):-
post_comp3(V2,N2,X2,V1,N1,X1),
N3 is N2 + 1,
post_comp2(Vs2,N3,V1,N1,X2,X1).
post_comp3(V2,N2,X2,V1,N1,X1) :-
( ( incompatible(V2,V1)
; incompatible(V1,V2)
)
-> X2 #\= N2 #\/ X1 #\= N1
; true
).
Note that the code is relatively straightforward, except for the (quadruple) loop to post the incompatibility constraints. This is due to the way I wanted to reuse the predicates in the question. In practice, one might want to change the way the data is presented.
The problem can then be solved with the following query (in SWI-prolog):
?- state(Xs, T), labeling([min(T)], Xs).
T = 1900, Xs = [2, 1, 2] ?
In SICStus prolog, one can write instead:
?- state(Xs, T), minimize(labeling([], Xs), T).
Xs = [2,1,2], T = 1900 ?
Another short predicate could then transform back the [2,1,2] list into [a2,b1,c2] if that format was expected.
I have the following predicate execute(actualState, instruction, nextState):-
such that when executing with the instructions: move, swap , i have the following solutions:
?- executed(regs(1,4,*,+,2), swap(1,2), NS).
solution:
NS = regs(4,1,*,+,2)?;
no
?- executed(regs(1,4,3,6,+), move(4), NS).
solution:
NS = regs(1,4,3,6,6)?;
no
How can I implement it?
what I want it to do is that it has an initial state, an instruction and a final state "executed (actualState, instruction, nextState)" and what I want to do is pass it a list of registers as initial state, for example "regs (1,2,3,4)" and an instruction, for example, move and swap. swap (swap the position X, X + 1) and move (copy what is in X and deposit it in X + 1) and what I want it to return, as final state, are the examples described in the statement of my question.
I would take the following approach. The key elements of this solution are:
Use of nth1/3 for considering an element of a list at a specified position
=../2 for mapping between a term with arguments and a list
A "substitution" predicate that substitutes a value at specified position in a list with another
subst([_|T], Y, 1, [Y|T]).
subst([X|T], Y, N, [X|T1]) :-
N #> 1,
N1 #= N - 1,
subst(T, Y, N1, T1).
executed(AS, swap(X,Y), NS) :-
AS =.. [regs|P],
nth1(X, P, Xe),
nth1(Y, P, Ye),
subst(P, Ye, X, P1),
subst(P1, Xe, Y, P2),
NS =.. [regs|P2].
executed(AS, move(X), NS) :-
AS =.. [regs|P],
nth1(X, P, Xe),
X1 #= X + 1,
subst(P, Xe, X1, P1),
NS =.. [regs|P1].
If you are using SWI prolog, you'll need to include the clpfd library, :- use_module(library(clpfd)).. Also some Prologs, such as Ciao Prolog, does not have nth1/3. Ciao does provide, however, nth/3 which has the same behavior, so it may be substituted.
Note that I'm using CLP(FD) here for more generality. If your system doesn't support CLP(FD) you can use is in place of #=, although it's less desirable.
Note that this solution works as long as the arguments indexing the registers are "in range". So it will fail on executed(regs(1,2,+), move(3), NS).. As an exercise, if this is required, you should try to enhance this solution to meet that need. It will help you to learn Prolog versus being given every detail of the solution.
Here is a solution of swap. The key is term to list =...
The rest is to dissect the list and put it back together.
Move is a piece of cake based on this answer and I left it "as an exercise"
:- use_module(library(lists)).
executed(H,swap(X,Y),Result):-
H =.. [regs|TH],
LL1 is X-1,
LL2 is Y-X-1,
length(TH,LL),
LL3 is LL-Y,
length(L1,LL1),
length(L2,LL2),
length(L3,LL3),
append(L1,LI1,TH),[EX|LIX]=LI1,append(L2,LI2,LIX),[EY|L3]=LI2,
flatten([regs,L1,EY,L2,EX,L3],LR),
Result =.. LR.
I just began learning Prolog and I wanted to understand Pathfinding better. I have a few examples of relationships, however, I don't know how to find the path and length of a relationships when the relationships are cyclical. I've been trying to create a list that documents visited nodes, but I keep receiving errors.
Below are a few examples as well as my attempt to find path given the relationship, source, target, pathlist, and length):
is_a(parallelogram, quadrilateral).
is_a(trapezoid, quadrilateral).
is_a(rhombus, parallelogram).
is_a(rectangle, parallelogram).
is_a(square, rhombus).
is_a(square, rectangle).
edge(a, b).
edge(b, c).
edge(c, d).
edge(d, a).
friend(alice, bob).
friend(bob, carol).
friend(carol, daniel).
friend(carol, eve).
friends(A,B) :-
friend(A,B);
friend(B,A).
transit(Rel, S, T) :-
call(Rel, S, X),
(X = T; transit(Rel, X, T)).
path_(Rel,Source,Target,Path,Len) :-
path_(Rel,Source,Target,Path,Len,[]).
path_(Rel,Source,Target,Path,Len,Visited) :-
transit(Rel,Source,Target),
transit(Rel,Source,Mid),
Mid == Target, !,
append(Visited,[Source,Target],Path),
length(Path,L),
Len is L+1.
path_(Rel,Source,Target,Path,Len,Visited) :-
transit(Rel,Source,Target),
transit(Rel,Source,Mid),
not(member(Mid,Visited)),
path_(Rel,Mid,Target,Path,Len,[Source|Visited]).
The above is my second attempt, but I receive errors on everything. My first attempt only worked with non-cyclical paths, such as for the is_a relationships, which is noted below:
path0(Rel,From,To,[From,To],2) :-
transit(Rel,From,To),
call(Rel, From, To).
path0(Rel,From,To,[From|Xs],Len) :-
transit(Rel,From,X),
call(Rel,From,X),
path0(Rel,X,To,Xs,_),
length(Xs, L),
Len is L+1.
I have a problem with my prolog solver for sudoku. It's working, but the performance is reeaaaaly bad. With small ones it's working just fine, but bigger ones like 9x9 or more take 10 minutes or more sadly. I want to leave it for an indefinite size like it is right now. Can anyone help?
solve_sudoku(Rows,Sol):-
length(Rows,Max),
maplist(same_length(Rows),Rows),
append(Rows, List), List ins 1..Max,
maplist(all_distinct, Rows),
transpose(Rows, Columns),
maplist(all_distinct,Columns),
maplist(label,Rows),
boxes(Boxes,Rows),
maplist(all_distinct,Boxes),
boxes_distinct(Boxes),
Sol = Rows.
boxes(Bs,M) :-
length(M,Len),
Sq is round(sqrt(Len)),
findall(B, (between(1, Sq, R),
between(1, Sq, C),
block(M, Sq, R, C, B)), Bs).
cell(M, R,C, V) :-
nth1(R,M,Row), nth1(C,Row,V).
block(M, Sq, R,C, B) :-
findall(V, (between(1, Sq, X),
between(1, Sq, Y),
I is (R-1) * Sq + X,
J is (C-1) * Sq + Y,
cell(M, I, J, V)), B).
boxes_distinct([]).
boxes_distinct([BH|BT]):-
all_distinct(BH),
boxes_distinct(BT).
The input is a list of lists with the sudoku to solve and the output is the solved sudoku as a list.
I think you shoud call
maplist(label,Rows)
after
boxes_distinct(Boxes)
usually you should call label or labelling after declaring all constraint.
and use "labeling predicate with ff or ffc option" instead of "label"
may increse efficiency.
boxes_distinct(Boxes) seems useless, being already covered by maplist(all_distinct,Boxes), and use label(List) (instead of maplist(label,Rows)) near the end of clause. Anyway, the main problem has been indicated by #gabrielte (+1)
I have a knowledge base that consists of students database in a file 'students.pl' like this:
% student(Name,Percent,List_of_Marks_in_3_subjects).
student('abc',83,[80,80,90]).
student('pqr',70,[70,60,80]).
student('xyz',76,[80,70,80]).
I want to access each student predicate from the knowledge base and calculate the average marks in each subject or average percentage, without using 'findall' or assert/retract.
I may want to use backtracking like this:
find_score_all(X) :- student(Name,Percent,L),
write(Percent),nl,
fail.
find_score_all(_).
With this approach I can access each element and write it, but if I want to add each 'Percent' value as an element to a list or just use a predicate like 'Percent1 is Total + Percent' to total the percent values and then find its average, how can I do so?
Note that I dont want to use findall or retract/assert and preferably find the average in one pass through the knowledge base since the knowledge base is very large.
Any help is appreciated.
%solution for sum of percents, you can replace with any other calculation sum_percent predicate.
listing(student/3, convert_to_list/2, sum_percent, sum_percent/2).
% student(Name,Percent,List_of_Marks_in_3_subjects).
student('abc',83,[80,80,90]).
student('pqr',70,[70,60,80]).
student('xyz',76,[80,70,80]).
convert_to_list(X, R):-
student(N, P, LM),
not(member(st(N, P, LM), X)),
convert_to_list([st(N, P, LM)|X], R).
convert_to_list(X, X).
sum_percent:-
convert_to_list([], X),
sum_percent(X, S),
write(S).
sum_percent([], 0).
sum_percent([st(_,E,_)|T], S):-
sum_percent(T, S2),
S is E+S2.
if you want to add to a list then you should use findall, or better, library(aggregate). But if you fear about efficiency, you could use something like this
integrate(ave, Goal, Ave) :-
State = state(0, 0, _),
repeat,
( call(Goal, V),
arg(1, State, C), U is C+1, nb_setarg(1, State, U),
arg(2, State, S), T is S+V, nb_setarg(2, State, T),
fail
; arg(1, State, C), arg(2, State, S), Ave is S/C
).
:- meta_predicate integrate(+, :, ?).
test:
members(X) :- member(X, [1,2,3,4]).
?- integrate(ave, members, R).
R = 2.5 .
Of course, you'll need to add error handling (at least, when counter C == 0).