Just starting with the example data in the original question (converted to rule):
lines([ h(19-13-30, -2- 1- -2),
h(18-19-22, -1- -1- -2),
h(20-25-34, -2- -2- -4),
h(12-31-28, -1- -2- -1),
h(20-19-15, 1- -5- -3)
]).
and the clpBNR form of the cross
predicate:
cross(Min, Max, h(Px1-Py1-_,Vx1-Vy1-_), h(Px2-Py2-_, Vx2-Vy2-_)) :-
{ (Y - Py1) / Vy1 == (X - Px1) / Vx1 },
{ (Y - Py2) / Vy2 == (X - Px2) / Vx2 },
{ X >= Min }, { X =< Max },
{ Y >= Min }, { Y =< Max }.
yields:
?- lines(Ls), member(A,Ls), member(B,Ls), A @> B, cross(7,27,A,B).
Ls = [h(19-13-30, -2-1- -2), h(18-19-22, -1- -1- -2), h(20-25-34, -2- -2- -4), h(12-31-28, -1- -2- -1), h(20-19-15, 1- -5- -3)],
A = h(19-13-30, -2-1- -2),
B = h(18-19-22, -1- -1- -2) ;
Ls = [h(19-13-30, -2-1- -2), h(18-19-22, -1- -1- -2), h(20-25-34, -2- -2- -4), h(12-31-28, -1- -2- -1), h(20-19-15, 1- -5- -3)],
A = h(20-25-34, -2- -2- -4),
B = h(19-13-30, -2-1- -2) ;
Ls = [h(19-13-30, -2-1- -2), h(18-19-22, -1- -1- -2), h(20-25-34, -2- -2- -4), h(12-31-28, -1- -2- -1), h(20-19-15, 1- -5- -3)],
A = h(20-25-34, -2- -2- -4),
B = h(20-19-15, 1- -5- -3) ;
Ls = [h(19-13-30, -2-1- -2), h(18-19-22, -1- -1- -2), h(20-25-34, -2- -2- -4), h(12-31-28, -1- -2- -1), h(20-19-15, 1- -5- -3)],
A = h(20-19-15, 1- -5- -3),
B = h(19-13-30, -2-1- -2) ;
Ls = [h(19-13-30, -2-1- -2), h(18-19-22, -1- -1- -2), h(20-25-34, -2- -2- -4), h(12-31-28, -1- -2- -1), h(20-19-15, 1- -5- -3)],
A = h(20-19-15, 1- -5- -3),
B = h(18-19-22, -1- -1- -2) ;
false.
This is a bit hard to check against the example output, so I added [X,Y]
:
cross0(Min, Max, h(Px1-Py1-_,Vx1-Vy1-_), h(Px2-Py2-_, Vx2-Vy2-_),[X,Y]) :-
{ (Y - Py1) / Vy1 == (X - Px1) / Vx1 },
{ (Y - Py2) / Vy2 == (X - Px2) / Vx2 },
{ X >= Min }, { X =< Max },
{ Y >= Min }, { Y =< Max }.
producing:
?- lines(Ls), member(A,Ls), member(B,Ls), A @> B, cross0(7,27,A,B,[X,Y]).
Ls = [h(19-13-30, -2-1- -2), h(18-19-22, -1- -1- -2), h(20-25-34, -2- -2- -4), h(12-31-28, -1- -2- -1), h(20-19-15, 1- -5- -3)],
A = h(19-13-30, -2-1- -2),
B = h(18-19-22, -1- -1- -2),
Y:: 15.3333333333333339...,
X:: 14.3333333333333339... ;
Ls = [h(19-13-30, -2-1- -2), h(18-19-22, -1- -1- -2), h(20-25-34, -2- -2- -4), h(12-31-28, -1- -2- -1), h(20-19-15, 1- -5- -3)],
A = h(20-25-34, -2- -2- -4),
B = h(19-13-30, -2-1- -2),
Y:: 16.6666666666666679...,
X:: 11.6666666666666661... ;
Ls = [h(19-13-30, -2-1- -2), h(18-19-22, -1- -1- -2), h(20-25-34, -2- -2- -4), h(12-31-28, -1- -2- -1), h(20-19-15, 1- -5- -3)],
A = h(20-25-34, -2- -2- -4),
B = h(20-19-15, 1- -5- -3),
Y:: 24.0000000000000000...,
X:: 19.0000000000000000... ;
Ls = [h(19-13-30, -2-1- -2), h(18-19-22, -1- -1- -2), h(20-25-34, -2- -2- -4), h(12-31-28, -1- -2- -1), h(20-19-15, 1- -5- -3)],
A = h(20-19-15, 1- -5- -3),
B = h(19-13-30, -2-1- -2),
Y:: 11.7777777777777786...,
X:: 21.4444444444444429... ;
Ls = [h(19-13-30, -2-1- -2), h(18-19-22, -1- -1- -2), h(20-25-34, -2- -2- -4), h(12-31-28, -1- -2- -1), h(20-19-15, 1- -5- -3)],
A = h(20-19-15, 1- -5- -3),
B = h(18-19-22, -1- -1- -2),
Y:: 20.6666666666666679...,
X:: 19.6666666666666679... ;
false.
Since there is no constraint on the time, this produces all the solutions including those for T<0
. This is consistent with the 5 solutions documented in the original question and takes about 0.2 sec. on my hardware.
The easiest way to omit solutions for T<0
is to note that each of the constraint LHS (or RHS) defines implicitly the value of T
so adding that (plus taking advantage of clpBNR declarations to simplify a bit):
cross1(Min, Max, h(Px1-Py1-_,Vx1-Vy1-_), h(Px2-Py2-_, Vx2-Vy2-_),[X,Y]) :-
[X,Y]::real(Min,Max),
{ (Y - Py1) / Vy1 == (X - Px1) / Vx1,
(Y - Py2) / Vy2 == (X - Px2) / Vx2,
(Y - Py1) / Vy1 >= 0, (Y - Py2) / Vy2 >= 0 % constrain implicit T
}.
produces:
?- lines(Ls), member(A,Ls), member(B,Ls), A @> B, cross1(7,27,A,B,[X,Y]).
Ls = [h(19-13-30, -2-1- -2), h(18-19-22, -1- -1- -2), h(20-25-34, -2- -2- -4), h(12-31-28, -1- -2- -1), h(20-19-15, 1- -5- -3)],
A = h(19-13-30, -2-1- -2),
B = h(18-19-22, -1- -1- -2),
X:: 14.3333333333333339...,
Y:: 15.3333333333333339... ;
Ls = [h(19-13-30, -2-1- -2), h(18-19-22, -1- -1- -2), h(20-25-34, -2- -2- -4), h(12-31-28, -1- -2- -1), h(20-19-15, 1- -5- -3)],
A = h(20-25-34, -2- -2- -4),
B = h(19-13-30, -2-1- -2),
X:: 11.6666666666666661...,
Y:: 16.6666666666666679... ;
false.
which is the two “positive” answers in the original question (and saves a little time). Also not that this problem only requires constraint propagation, i.e., no labeling step is necessary.
So I have some confidence that the code is correct. But the next question is how does it scale from 5 data points in the question example to 300 points(“input.txt”). That’s a huge increase in complexity C(300,2) = 44850
vs. C(5,2) = 10
(according to an online calculator) - a factor of 4485. So if the time for N=5
is ~0.2 secs., I would expect the time for N=300
to be around 15 minutes.
The reason clpq
is that quick is that that’s the time taken just to process the constraints - there’s no propagation time since non-linear constraints remain passive.