Reputation: 39
I'm trying to do a for loop in Prolog which doesn't work. The program should do following:
generate(N,[S,E],FinalSegments):-
segments([S,E],Initialsegments),
iterate_level(N,Initialsegments,FinalSegments).
When I'm calling generate(5,[(10,0),(-10,0)])
the first step is, that generate(5,[(10,0),(-10,0)],FinalSegments)
is being called and this predicate generates 4 coordinates between the Startpoint (10,0)
and the Endpoint (-10,0)
, and store those four ccordinates in the listFinalSegments
. This is actually done correctly. In the next step the predicate iterate_level(N,Initialsegments,FinalSegments)
is being called.
The predicate iterate_level()
, takes the four coordinates from the last step as a list called Initialsegments
:
Initialsegments:([[ (10, 0), (3.333333333333333, 0)],
[ (3.3333, 0), (-3.5527e-15, -5.7735)],
[ (-3.5527e-15, -5.77350), (-3.3333, 0)],
[(-3.3333, 0), (-10, 0)]])
And now iterate_level(5,Initialsegments,FinalSegments)
should be a for-loop which should generate 16 coordinates after the first iteration, then 64 coordinates after the second iteration...
But here is my problem that this is not really working and I don't know what I'm still doing wrong.
It seem to me, when I'm looking at the trace, that
iterate_level(N,Ls,F):-
seq(0,N,Index),
next_level_segments(Index,Ls,F).
when next_level_segments(Index,Ls,F)
is called within the for-loop, the list
Ls which should contain four times more coordinates after each iteration is not refreshed.(Maybe this is the problem).
When I call generate(3,[[(60,0),(-60,0)]],X).
I get four times always the same 16 coordinates as a result but I should get 1024 different coordinates.
Maybe someone may have some time to have a look at this problem an give me some help.
Thanks
This is my implementation until now:
generate(N,[S,E],FinalSegments):-
segments([S,E],Initialsegments),
iterate_level(N,Initialsegments,FinalSegments).
generate(N,[],[]).
seq(From,_,From).
seq(From,To,X) :-
From<To,
Next is From+1,
seq(Next,To,X).
iterate_level(N,Ls,F):-
seq(0,N,Index),
next_level_segments(Index,Ls,F).
%fail.
iterate_level(Ls,F).
iterate_level([],[]).
segments([(Sx,Sy),(Ex,Ey)],Ls):-
X2 is Sx+(Ex-Sx)/3,
Y2 is Sy+(Ey-Sy)/3,
R1 is sqrt((X2-Sx)*(X2-Sx)+(Y2-Ey)*(Y2-Ey)),
Phi1 is atan((Y2-Sy)/(X2-Sx)),
X3 is X2 +R1*cos((Phi1-240)*pi/180),
Y3 is Y2 +R1*sin((Phi1+240)*pi/180),
X4 is X2+(X2-Sx),
Y4 is Y2+(Y2-Sy),
Ls=[
[(Sx,Sy),(X2,Y2)],
[(X2,Y2),(X3,Y3)],
[(X3,Y3),(X4,Y4)],
[(X4,Y4),(Ex,Ey)]
].
next_level_segments(N,[[(Sx,Sy),(Ex,Ey)]|E],[X|RLs]):-
segments([(Sx,Sy),(Ex,Ey)],X),
next_level_segments(N,E,RLs).
next_level_segments(N,[],[]).
Upvotes: 0
Views: 217
Reputation: 765
So, first of all, Prolog doesn't do for-loops in the traditional sense - what you actually want to do is recurse over the list with an accumulator. This can be achieved as follows.
Firstly, generate(0, [[X|Y]|Z], [[X|Y]|Z]) :- !.
, which says "if I am trying to generate the 0th iteration of a list of lists, I have achieved my goal and I should succeed". This also cuts, as there is only ever going to be a single solution here.
generate(N, [[P1, P2]|Tail], Final)
does the main body of the (outer) recursion. As long as this is a positive iteration (ie exclude negatives), we do_generate
an iteration of coordinates, and recurse for another iteration (with iteration 0 succeeding as above).
do_generate([],[]).
states that if we're trying to generate coordinates between an empty list, we're done for this level.
do_generate([Current|Rest], Interim)
takes the first pair of coordinates and generates the set of four pairs of coordinates (using segments([(Sx,Sy),(Ex,Ey)],Ls)
as before), then recurses onto the rest of the list of coordinates. Once we reach the above base-case, we append all the lists together from last to first to get the new set of coordinates. This is then unified with Interim
, to send back to generate(N, [[P1, P2]|Tail], Final)
for further recursion or unification with Final
using the outer base-case.
As a caveat, in order to get output looking like input for the final base-case, the input is now required to be a list of lists of coordinate-pairs, not just a list of coordinate-pairs.
All put together, you get the following:
generate(0, [[X|Y]|Z], [[X|Y]|Z]) :- !.
generate(N, [[P1, P2]|Tail], Final) :-
N > 0,
do_generate([[P1, P2]|Tail], Interim),
N1 is N-1,
generate(N1, Interim, Final).
do_generate([], []).
do_generate([Current|Rest], Interim) :-
segments(Current, Segs),
do_generate(Rest, RestSegs),
append(Segs, RestSegs, Interim).
segments([(Sx,Sy), (Ex,Ey)], Ls) :-
X2 is Sx+(Ex-Sx)/3,
Y2 is Sy+(Ey-Sy)/3,
R1 is sqrt((X2-Sx)*(X2-Sx)+(Y2-Ey)*(Y2-Ey)),
Phi1 is atan((Y2-Sy)/(X2-Sx)),
X3 is X2+R1*cos((Phi1-240)*pi/180),
Y3 is Y2+R1*sin((Phi1+240)*pi/180),
X4 is X2+(X2-Sx),
Y4 is Y2+(Y2-Sy),
Ls=[[(Sx,Sy),(X2,Y2)],
[(X2,Y2),(X3,Y3)],
[(X3,Y3),(X4,Y4)],
[(X4,Y4),(Ex,Ey)]].
Upvotes: 3