我正在尝试编写一个过程来检查图中的2个节点是否相邻,或者是邻居。
我正在使用SWI-prolog。
我在尝试:
adjacent(X,Y,graph(_,E)):-
member(e(X,Y), E).
然而,这不起作用,我对其原因感到困惑。
我将其用作测试图。
tem(graph([s,t,u,v], [e(a,b), e(b,d), e(b,c), e(c,d)])).
我在这样的代码上查看它:
?- tem(graph(_, E)), adjacent(a, b, E).
false.
但是那两个都是邻居所以它应该返回真实。
答案 0 :(得分:1)
要重复,令人惊讶的失败的查询是:
?- tem(graph(_, E)), adjacent(a, b, E). false.
在Prolog中,找到这些问题的深层次原因的好方法是以声明的方式思考并系统地尝试合适的概括和专业化您的计划和目标。
例如,您可以将a
和b
替换为变量 A
,从而使上面的查询显着更通用和B
分别为:
?- tem(graph(_, E)), adjacent(A, B, E). false.
所以,这个仍然失败了!因此,特别是,任何更具体的查询都将失败,因为该程序完全是纯和单调,这使得这种推理可以接受。
让我们继续这一点,概括 adjacent/2
的单一目标。
而不是:
adjacent(X,Y,graph(_,E)):- member(e(X,Y), E).
我现在写道:
adjacent(X,Y,graph(_,E)) :- true.
这当然会使整个谓词显着更通用:在原始谓词成功的每种情况下,此变体也会成功 !
即使有这个明显更一般的定义,我们仍然:
?- tem(graph(_, E)), adjacent(A, B, E). false.
现在找不到更多内容:错误必须在剩余部分中,并且错误在以下片段中:
adjacent(X, Y, graph(_,E)) :- ...
如果仔细观察,会导致失败的是 head 这个子句:您使用 list 作为第三个参数调用谓词,但在此定义中,第三个参数是不列表。
此方法称为声明性调试,您可以在 program-slicing 下找到更多信息。 Prolog和逻辑编程语言通常非常独特,允许应用这种强大的调试技术。请注意,此方法可以轻松地自动化:通过简单断言此查询应该成功,程序可以派生上面的片段并向您显示精确的原因问题。
答案 1 :(得分:0)
除了mat的优秀答案之外,相邻的程序还希望将仿函数图作为第三个参数。
tem(G), adjacent(a, q, G).
会将列表作为第3个参数传递给 GroupOperation countByBookOwner = group("owner").count().as("nbBooks");
SortOperation sortByCount = sort(Direction.ASC, "nbBooks");
GroupOperation putInArray = group().push("nbBooks").as("nbBooksArray");
ProjectionOperation getSizeOfArray = project("nbBooksArray").and("nbBooksArray").size().as("size");
ProjectionOperation divideSizeByTwo = project("nbBooksArray").and("size").divide(2).as("middleFloat");
ProjectionOperation getIntValueOfDivisionForBornLeft = project("middleFloat", "nbBooksArray").and("middleFloat")
.project("trunc").as("beginMiddle");
ProjectionOperation add1ToBornLeftToGetBornRight = project("beginMiddle", "middleFloat", "nbBooksArray")
.and("beginMiddle").project("add", 1).as("endMiddle");
ProjectionOperation arrayElementAt = project("beginMiddle", "endMiddle", "middleFloat", "nbBooksArray")
.and("nbBooksArray").project("arrayElemAt", "$beginMiddle").as("beginValue").and("nbBooksArray")
.project("arrayElemAt", "$endMiddle").as("endValue");
ProjectionOperation averageForMedian = project("beginMiddle", "endMiddle", "middleFloat", "nbBooksArray",
"beginValue", "endValue").and("beginValue").project("avg", "$endValue").as("median");
Aggregation aggregation = newAggregation(countByBookOwner, sortByCount, putInArray, getSizeOfArray,
divideSizeByTwo, getIntValueOfDivisionForBornLeft, add1ToBornLeftToGetBornRight, arrayElementAt,
averageForMedian);
long time = System.currentTimeMillis();
AggregationResults<MedianContainer> groupResults = mongoTemplate.aggregate(aggregation, "book",
MedianContainer.class);
,而不是图函子。
{
"aggregate": "book" ,
"pipeline": [
{
"$group": {
"_id": "$owner" ,
"nbBooks": {
"$sum": 1
}
}
} , {
"$sort": {
"nbBooks": 1
}
} , {
"$group": {
"_id": null ,
"nbBooksArray": {
"$push": "$nbBooks"
}
}
} , {
"$project": {
"nbBooksArray": 1 ,
"size": {
"$size": ["$nbBooksArray"]
}
}
} , {
"$project": {
"nbBooksArray": 1 ,
"middleFloat": {
"$divide": ["$size" , 2]
}
}
} , {
"$project": {
"middleFloat": 1 ,
"nbBooksArray": 1 ,
"beginMiddle": {
"$trunc": ["$middleFloat"]
}
}
} , {
"$project": {
"beginMiddle": 1 ,
"middleFloat": 1 ,
"nbBooksArray": 1 ,
"endMiddle": {
"$add": ["$beginMiddle" , 1]
}
}
} , {
"$project": {
"beginMiddle": 1 ,
"endMiddle": 1 ,
"middleFloat": 1 ,
"nbBooksArray": 1 ,
"beginValue": {
"$arrayElemAt": ["$nbBooksArray" , "$beginMiddle"]
} ,
"endValue": {
"$arrayElemAt": ["$nbBooksArray" , "$endMiddle"]
}
}
} , {
"$project": {
"beginMiddle": 1 ,
"endMiddle": 1 ,
"middleFloat": 1 ,
"nbBooksArray": 1 ,
"beginValue": 1 ,
"endValue": 1 ,
"median": {
"$avg": ["$beginValue" , "$endValue"]
}
}
}
]
将作为第三个参数传入图形仿函数,而不仅仅是图形仿函数的一部分。