Prolog如何防止重复的答案

时间:2013-09-23 18:54:51

标签: prolog prolog-setof

对于我的程序,知识库具有原子语句和规则,例如

store(itemName, ProductType)

ex:store(iPhone5,手机)

manufacturer(itemName, Company)

ex:制造商(iPhone5,苹果)

查询是要确定是否有一家公司制造了超过2种不同的产品类型,因此对于苹果来说,将有Macbook,iPad和iPhone

以下是我们的查询:

?- store(ItemID1, ProductType1), manufacturer(ItemID1, Company), store(ItemID2, ProductType2), manufacturer(ItemID2, Company), store(ItemID3, ProductType3), manufacturer(ItemID3, Company), not ProductType1 = ProductType2, not ProductType1 = ProductType3, not ProductType2 = ProductType3.

它给出了正确的答案,列出了3个苹果产​​品,但是按下更多会一次又一次给出相同的答案。有办法阻止这个吗?

注意:我知道本网站提供的其他问题的其他答案,但由于我对Prolog知之甚少而不确定这些答案是否适用于此问题,因此不知道如何实施这些问题。

注意:对于此问题,我不得使用! ->;运营商

2 个答案:

答案 0 :(得分:1)

折扣性能问题,您的核心问题似乎是您寻找不同的产品类型,但产品本身有变量。因此,例如对于假设的不同产品类型T1,T2,T3和T1类型的产品P1a P1b P1c,T2类型的P2和T3类型的P3,您将获得(P1a,P2,P3),(P1b, P2,P3)和(P1C,P2,P3),从你的角度来看都是等价的。

为避免您需要将(类型,产品)对融合为每种类型的一对。

PS:如果你将代码减少到暴露问题的最小值(例如,price谓词似乎没必要),你会得到更好的答案,并为我们提供你的实际输出。

答案 1 :(得分:1)

我认为除了JB的推荐之外,还有其他一些方法可以解决它。一个俗气的伎俩是通过将其添加到查询的末尾来强制执行ProductTypeN的排序:

ProductType1 @> ProductType2, 
ProductType2 @> ProductType3.

这将为您提供三种产品类型的一种排列,消除您所看到的组合爆炸。

更复杂的技术是使用setof/3来枚举解决方案。因为它会将所有答案作为一个集合生成,所以它必须对值进行排序,这样可以基本上以与俗气相同的方式删除重复项。

more_than_two_product_types(Manufacturer) :-
    setof(Manufacturer, T^manufacturer(T,Manufacturer), Manufacturers),
    member(Manufacturer, Manufacturers),
    setof(Type, Thing^(manufacturer(Thing, Manufacturer), store(Thing, Type)), [_,_,_|_]).

这很复杂,所以让我们把它分解。首先,这个条件产生了一系列制造商:

setof(Manufacturer, T^manufacturer(T,Manufacturer), Manufacturers),

setof/3元谓词采用构造函数表达式,模板表达式,并返回结果列表。这个将收集manufacturer(T, Manufacturer)的所有解决方案并将它们收集到列表中。我们只对制造商的名称感兴趣,因此模板参数只是ManufacturerT^语法告诉setof/3 T manufacturer(T, Manufacturer)中的setof/3是一个自由变量,所以我们不关心它实例化的内容。这是必不可少的,或者member(Manufacturer, Manufacturers), 本身会为每种类型生成一个解决方案,这不是我们想要的。

这一行重复了新的制造商名单:

setof(Type, Thing^(manufacturer(Thing, Manufacturer), store(Thing, Type)), [_,_,_|_]).

这条复杂的产品系列可以找到制造商生产的所有类型的产品:

(manufacturer(Thing, Manufacturer), store(Thing, Type))

此处的目标表达式是序列Thing。这就是说,找到这个制造商制作的Type,然后找到那个东西的Thing^。同样,Type语法表示我们并不关心事物是什么,因此请立即获取所有[_,_,_|_]个解决方案。模板?- [1,2,3] = [_,_,_|_]. true. ?- [1,2] = [_,_,_|_]. false. ?- [1,2,3,4] = [_,_,_|_]. true. 与包含至少三个项目的任何列表统一,而不是将其绑定到我们要处理的列表。我们并不在乎这些物品是什么,所以它们都是空白的。在您的控制台中进行测试并查看它与之结合的内容:

{{1}}

这将产生至少三个解决方案,然后将它们抛弃以取得成功,或者如果它产生的更少则失败。

正如您所看到的,使用Prolog给猫咪涂抹的方法不止一种。 :)