Как связать Prolog CLP (R) с реальными векторами? - PullRequest
0 голосов
/ 02 июля 2018

Я использую Пролог для решения простых геометрических уравнений. Например, я могу определить все точки p3 на линии, проходящей через две точки p1 и p2, как:

   line((X1, Y1, Z1), (X2, Y2, Z2), T, (X3, Y3, Z3)) :-
        {(X2 - X1) * T = X3},
        {(Y2 - Y1) * T = Y3},
        {(Z2 - Z1) * T = Z3}.

И тогда предикат типа line((0, 0, 0), (1, 1, 1), _, (2, 2, 2)) верен.

Но я бы действительно хотел записать что-то вроде этого:

line(P1, P2, T, P3) :- {(P2 - P1) * T = P3}.

Где P1, P2 и P3 - действительные векторы.

Какой лучший способ получить нечто подобное? Лучшее, что я нашел до сих пор, это переписать мои собственные предикаты add, subtract и multiply, но это не так удобно.

1 Ответ

0 голосов
/ 02 июля 2018

Вот решение, в котором вам все еще нужно написать немного кода для каждого оператора, который вы хотите обработать, но который по-прежнему обеспечивает хороший синтаксис в момент использования.

Давайте начнем с понятия вычисления арифметического выражения на векторах для вектора. Это по существу применяет арифметические операции компонентно. (Но вы можете добавить точечный продукт или что угодно.)

:- use_module(library(clpr)).

vectorexpr_value((X,Y,Z), (X,Y,Z)).
vectorexpr_value(V * T, (X,Y,Z)) :-
    vectorexpr_value(V, (XV,YV,ZV)),
    { X = XV * T },
    { Y = YV * T },
    { Z = ZV * T }.
vectorexpr_value(L + R, (X,Y,Z)) :-
    vectorexpr_value(L, (XL,YL,ZL)),
    vectorexpr_value(R, (XR,YR,ZR)),
    { X = XL + XR },
    { Y = YL + YR },
    { Z = ZL + ZR }.
vectorexpr_value(L - R, (X,Y,Z)) :-
    vectorexpr_value(L, (XL,YL,ZL)),
    vectorexpr_value(R, (XR,YR,ZR)),
    { X = XL - XR },
    { Y = YL - YR },
    { Z = ZL - ZR }.

Так, например:

?- vectorexpr_value(A + B, Result).
A =  (_1784, _1790, _1792),
B =  (_1808, _1814, _1816),
Result =  (_1832, _1838, _1840),
{_1808=_1832-_1784},
{_1814=_1838-_1790},
{_1816=_1840-_1792} .

Учитывая это, теперь мы можем определить «равенство» векторных выражений, «оценив» их оба и заявив точечное равенство результатов. Чтобы это выглядело хорошо, мы можем определить для него оператор:

:- op(700, xfx, ===).

Это определяет === как инфиксный оператор с тем же приоритетом, что и у других операторов равенства =, =:= и т. Д. Prolog не позволяет перегрузить операторы, поэтому мы создали новый. Вы можете думать о трех = знаках в операторе как о выражении равенства в трех измерениях.

Вот соответствующее определение предиката:

ExprL === ExprR :-
    vectorexpr_value(ExprL, (XL,YL,ZL)),
    vectorexpr_value(ExprR, (XR,YR,ZR)),
    { XL = XR },
    { YL = YR },
    { ZL = ZR }.

И теперь мы можем определить line/4 почти так, как вы хотели:

line(P1, P2, T, P3) :-
    (P2 - P1) * T === P3.

Тесты:

?- line((0,0,0), (1,1,1), Alpha, (2,2,2)).
Alpha = 2.0 ;
false.

?- line((0,0,0), (1,1,1), Alpha, (2,3,4)).
false.
...