2

I'm using Prolog to solve simple geometrical equations. For example, I can define all points p3 on a line passing trough two points p1 and p2 as:

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

And then a predicate like line((0, 0, 0), (1, 1, 1), _, (2, 2, 2)) is true.

But what I'd really want is to write down something like this:

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

Where P1, P2, and P3 are real vectors.

What's the best way of arriving at something similar? The best I found so far is to rewrite my own add, subtract and multiply predicates, but that's not as conveniant.

4

1 回答 1

2

这是一个解决方案,您仍然需要为要处理的每个运算符编写一些代码,但它仍然在使用时提供了很好的语法。

让我们从将向量上的算术表达式计算为向量的概念开始。这实质上是按组件应用算术运算。(但你可以添加一个点积或任何你喜欢的东西。)

:- 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.
于 2018-07-02T08:58:02.367 回答