分层无向图表示

时间:2012-07-22 10:35:46

标签: graph prolog

我需要像这样代表图表:

Graph = graph([Object1,Object2,Object3,Object4],
              [arc(Object1,Object2,connected),
               arc(Object2,Object4,connected),
               arc(Object3,Object4,connected),
               arc(Object1,Object3,connected),
               arc(Object2,Object3,parallel),
               arc(Object1,Object4,parallel),
               arc(Object2,Object3,similar_size),
               arc(Object1,Object4,similar_size)])

我没有对代码的限制,但是我坚持这种表示,因为它适合我已编码的所有其他结构。

我的意思是无向图,其中顶点是一些对象,边表示它们之间的无向关系。为了给你更多这个特定例子的背景,我试图表示一个矩形,所以对象是它的四个边(段)。使用顶点等以相同的方式表示这些段。重点是构建图表的层次结构,它将表示同一级别上对象之间的约束。

问题在于边缘的表示。表示弧(a,b)的最明显的方法是将(a,b)和(b,a)都放在程序中。然而,这会使我的程序充满冗余数据。例如,如果我有顶点a,b,c,d。我可以构建段(a,b),(a,c),(a,d),(b,c),(b,d),(c,d)。但我也得到(b,a),(c,a),依此类推。在这一点上它不是一个问题。但后来我建了一个矩形。它可以是段(a,b),(b,c),(c,d),(a,d)的构建。我想得到答案 - 有一个矩形。但是你可以计算出我得到的这个矩形的组合数量。它也需要花费太多时间来计算,显然我不想在矩形水平上完成。

我考虑过对元素进行排序。我可以在一个段中对顶点进行排序。但是如果我想对矩形中的段进行排序,则约束不再有效。图表变为定向。例如,考虑前两个关系,假设我们有弧(a,b)和(a,c)。如果未对弧进行排序,程序将按照我的要求进行回答:arc(b,a,connected),arc(a,c,connected)匹配:Object1 = b,Object2 = a,Object4 = c。如果我对元素进行排序它不再有效,因为我没有尝试使用arc(b,a,connected)和arc(a,b,connected)。只有第二个。我坚持排序,但我不知道如何解决这个问题。

希望我非常清楚地说明了这一切。我宁愿保持接近我已经拥有的表现和想法。但是全新的也非常受欢迎。我不希望得到任何确切的答案,而是让我朝着正确的方向倾斜,或者建议一些特定的内容,因为我对Prolog很新,也许这个问题并不像我想的那么罕见。

我从昨天起就试图解决这个问题,并且无法提出任何简单的答案。我查看了一些离散的数学和常见的无向图表示,如邻接列表。如果有什么不清楚,请告诉我 - 我会尝试提供更多细节。

1 个答案:

答案 0 :(得分:1)

有趣的问题虽然有点宽泛,因为没有说明你对弧,矩形等的实际想要做什么;只有某些用途,表示才有效(时间/空间/优雅)。无论如何,这里有一些想法:

分拣
显而易见的问题是你提到的问题;如果存在已排序的对,则可以通过引入成功的子句来解决它:

arc(X,Y):-
    arc_data(X,Y)
  ; arc_data(Y,X).

请注意,应执行以下操作:

arc(a,b).
arc(b,c).
arc(X,Y):-
   arc(Y,X)

因为如果弧不存在,这将导致无限循环。 但是你只能检查第一个arg是否大于第二个arg:

arc(a,b).
arc(b,c).
arc(X,Y):-
   compare(>,X,Y),
   arc(Y,X)

这种方法无法解决由于以两种方式表示弧而可能出现的多种解决方案。 简单的解决方法是仅检查一个解决方案,其中只有一个解决方案使用once/1

3 ?- arc(X,Y).
X = a,
Y = b ;
X = b,
Y = a.

4 ?- once(arc(X,Y)).
X = a,
Y = b.

当有多种解决方案时,你无法做到这一点。

另一种方法是强制进一步抽象:此时,当你有两个点(ab)时,你可以创建弧(arc(a,b)或{{1} })检查这些点是否已连接。而不是那样,你应该通过谓词创建弧(也可以检查点是否连接)。好处是您不再直接参与弧的表示,因此可以强制排序(是的,它基本上是面向对象):

arc(b,a)

(假设为数据库cv_arc(X,Y,Arc):- ( arc(X,Y), Arc = arc(X,Y)) ; ( arc(Y,X), Arc = arc(Y,X)). ):

arc(a,b)

当然,您需要遵循其他对象的类似原则;我假设您正在做这样的事情来找到一个矩形:

    6 ?- cv_arc(a,b,A).
    A = arc(a, b).

    7 ?- cv_arc(b,a,A).
    A = arc(a, b).

    8 ?- cv_arc(b,c,A).
    false.

除了由于弧线(被解析)造成的重复之外,这会将ABCD,DABC等识别为不同的矩形:

rectangle(A,B,C,D):-
    arc(A,B),
    arc(B,C),
    arc(C,D),
    arc(D,A).

我们将再次这样做:

28 ?- rectangle(A,B,C,D).
A = a,
B = b,
C = c,
D = d ;
A = b,
B = c,
C = d,
D = a ;
A = c,
B = d,
C = a,
D = b ;
A = d,
B = a,
C = b,
D = c.

并使用rectangle(rectangle(A,B,C,D)):- cv_arc(A,B,AB), cv_arc(B,C,BC), compare(<,AB,BC), cv_arc(C,D,CD), compare(<,BC,CD), cv_arc(D,A,DA), compare(<,CD,DA).

运行
arc(a,b). arc(b,c). arc(c,d). arc(a,d).

请注意,如果弧的顺序错误,我们没有重新排序矩形;我们只是失败了。这样我们就避免了重复的解决方案(如果我们对它们进行排序并将其作为有效矩形接受,我们将使用相同的矩形四次)但是找到矩形所花费的时间会增加。我们通过在第一个无序的弧处停止搜索而不是创建整个矩形来减少开销。此外,如果对弧进行排序,则开销也会减少(因为第一次匹配将被排序)。另一方面,如果我们考虑以这种方式搜索所有矩形的复杂性,那么开销就不那么重要了。此外,它仅适用于我们只需要第一个矩形;如果我们想获得更多解决方案或确保没有其他解决方案,prolog将搜索整个树,无论是否报告解决方案。