Prolog-面积的实现公式

Prolog-面积的实现公式,prolog,Prolog,我想在Prolog中计算多边形的面积 多边形的面积由以下公式给出: | {(x1*y2-y1*x2) + (x2*y3-y2*x3) + .... + (xn*y1 - yn*x1)}/2 | 其中(x1,y1)、(x2,y2)…(xn,yn)是多边形的点 这是我在Prolog中实现公式的尝试: area(Points,Area):-areaAcc(Points,0,Area). areaAcc([(X1,Y1),(X2,Y2)|List], Acc, Area):- areaAcc

我想在Prolog中计算多边形的面积

多边形的面积由以下公式给出:

| {(x1*y2-y1*x2) + (x2*y3-y2*x3) + .... + (xn*y1 - yn*x1)}/2 |
其中
(x1,y1)、(x2,y2)…(xn,yn)
是多边形的点

这是我在Prolog中实现公式的尝试:

area(Points,Area):-areaAcc(Points,0,Area).

areaAcc([(X1,Y1),(X2,Y2)|List], Acc, Area):-
    areaAcc2([(X1,Y1),(X2,Y2)|List], Acc, Area, (X1,Y1)).

areaAcc2([(X1,Y1),(X2,Y2)|List],Acc,Area,(FirstX,FirstY)):- 
    NewAcc is (X1*Y2-Y1*X2) + Acc,
    areaAcc2([(X2,Y2)|List], NewAcc, Area, (FirstX,FirstY)).

areaAcc2([(Xm,Ym),(Xn,Yn)|[]],Acc,Area,(FirstX,FirstY)):- 
    Area is abs((Acc + (Xn*FirstY - Yn*FirstX))/2).
但当我跑步时:

 area([(4,10),(9,7),(11,2),(2,2),(4,10)],Area).
我得到的是
Area=51.5
而不是正确的答案:
Area=45.5

有人能认出我的错误吗

如果简化基本情况(最后一个子句),并传递一个非闭合多边形,则结果是正确的

areaAcc2([(Xn,Yn)],Acc,Area,(FirstX,FirstY)):- 
    Area is abs((Acc + (Xn*FirstY - Yn*FirstX))/2).
屈服

?- area([(4,10),(9,7),(11,2),(2,2)], A).
A = 45.5 
否则,使用库支持实现会更容易:

area_poly(Points, A) :-
    aggregate_all(sum(E), 
        (append(_, [(X1,Y1),(X2,Y2)|_], Points), E is (X1*Y2-Y1*X2)), A2),
    A is abs(A2/2).
请注意,is忽略了公式的最后一个和,但它产生了正确的值,因为我们传递了一个已经闭合的多边形

?- area_poly([(4,10),(9,7),(11,2),(2,2),(4,10)], A).
A = 45.5.

EditAggregate_all/3在SWI Prolog和YAP(我认为是共享源代码)以及SICStus Prolog中提供。我认为所有这些都源自昆图斯序言。关于实现,我略述了一下,但是重用库代码当然更好…

我已经有一段时间没有为这类问题操心了。但是从

这是我对解决方案的看法(假设点的顺序正确):


根据多边形的表示方式,您可能不需要调用
append/3

当您到达最后两个元素时,它将匹配
区域acc2/4
子句:
[(2,2),(4,10)]
匹配
[(Xm,Ym),(Xn,Yn)|[]
[(X1,Y1),(X2,Y2)|列表]
(对于
列表=[]
)。然后,它可能会计算最后两个点两次。如果需要纠正,则应确保其正常工作。提示:您的最后一个子句没有使用
(Xm,Ym)
。大多数Prolog编译器不提供带有
聚合\u all
谓词的库。用只适用于一两种Prolog方言但不提及该要求的解决方案回答Prolog一般问题会增加人们使用其他方言尝试解决方案的风险,并得出结论认为这些方言已被破坏,或者更糟糕的是,Prolog不是一种可靠的编程语言。@PauloMoura:你完全正确。我认为缺少聚合实际上是Prolog的一个“bug”。如果它更简单,但语法类似于SQL GROUP BY,可能会更好。我建议您通过提及哪些Prolog系统提供了可用于替代解决方案的
aggregate\u all/3
库谓词来改进您的答案?以及如何使该谓词可用于实现
area\u poly/2
谓词。
area_polygon( []            , _ ) :- ! , fail . % not a polygon.
area_polygon( [P1]          , _ ) :- ! , fail . % 1 single point is not a polygon.
area_polygon( [P1,P2]       , _ ) :- ! , fail . % 2 points is a line segment and not a polygon.
area_polygon( [P1,P2,P3|Ps] , A ) :-            % now we're getting somehere: 3 points is a triangle.
  append( [P1,P2,P3|Ps] , [P1] , X ) ,          % append the first point to the list so it ends where it started.
  area_polygon( X , 0.0 , A )                   % call the worker predicate, seeding its accumulator with 0.0
  .

area_polygon( [] , T , A ) :- A is abs( T ) / 2.0 .
area_polygon( [(X1,Y1),(X2,Y2)|Ps] , T , A ) :-
  T1 is T + (X1+X2) * (Y2-Y1) ,
  area_polygon( [(X2,Y2)|Ps] , T1 , A )
  .