我有一个有趣的小问题,我会看到像这样的逻辑子句:
Rule 1. A, B and C are unique, and are numbers from 1 to 3 (so every number is used).
Rule 2. B < 2
Rule 3. C > 2
现在(假设这个简单的例子我刚刚提出实际验证:P),很容易看到
A = 2
B = 1
C = 3
但这是一个非常人为的例子。
如果您有20(或一万)规则,并且它们重叠,那该怎么办?假设存在有效的单一答案,并且您可以以某种方式访问规则(无论是谓词列表)。
有一个很好的,通用的,直观的解决方案吗?我知道Prolog可以用某些库解决它,但我的尝试证明是徒劳的。我知道我可以通过暴力强制排列范围内的所有数字,然后手动检查它们是否符合规则。但这似乎很蹩脚。
答案 0 :(得分:4)
首先,我根据规则1创建所有可能的输入,这恰好是所有排列:
val all = (1 to 3).permutations
然后我定义了剩余的规则:
val rule2 = (a: Int, b: Int, c: Int) => b < 2
val rule3 = (a: Int, b: Int, c: Int) => c > 2
我只是过滤掉了与所有规则不符的解决方案:
val solutions = all.
filter(i => rule2(i(0), i(1), i(2))).
filter(i => rule3(i(0), i(1), i(2))).
toList
solutions.toList
打印出唯一有效的解决方案:
List(Vector(2, 1, 3))
请注意,由于排列是懒惰生成的,因此此实现并非真正无效(例如rule3
仅适用于通过rule2
)的解决方案。
您可以使用foldLeft()
应用任意数量的谓词:
val rules = List(rule2, rule3)
rules.
foldLeft(all)((solutionsSoFar, rule) =>
solutionsSoFar.filter(s =>
rule(s(0), s(1), s(2))
)
)
查看Drools业务规则引擎。只需将所有可能的解决方案作为知识库,并使用不错的DSL定义规则。
答案 1 :(得分:3)
这是约束的工作。 java有几个约束求解器。我最喜欢的是JaCoP。有一个很好的scala DSL,所以它几乎看起来像Prolog约束。以下是典型的SENDMOREMONEY示例:http://www.hakank.org/jacop/SendMoreMoney.scala
答案 2 :(得分:2)
您可能对此博客感兴趣,作者在一篇由三部分组成的文章中展示了如何在Scala中进行逻辑编程:
http://ambassadortothecomputers.blogspot.com/feeds/posts/default?alt=rss