我有一堆约束,每个约束由两个符号和一个比较运算符组成:<
, <=
, !=
, ==
, >=
, 或>
。因此,例如:
A <= B
C >= B
A != C
C == D
D > E
我希望能够做三件事:
- 首先,我想检查是否有任何不一致之处。因此,例如,如果我有
A > B
、B > C
和A == C
,则存在不一致,因为A
必须既等于C
又大于它。 - 我希望能够查询任何两个符号,并取回它们之间可行的相对顺序。因此,例如
query(A, C)
应该返回{<}
(由单个元素组成的集合:小于),并且query(B, E)
应该返回{<, =, >}
. - 我希望能够添加一个约束(这也可以添加(一个)附加符号,例如添加
F == G
到上面的示例中)。
查询比添加约束更常见。
如果您没有任何!=
限制,我已经想出了一个可行的方法:
- 将每个约束转换为仅使用
<
或<=
(因此:X == Y
变成X <= Y
andY <= X
,X > Y
变成Y < X
等)的约束。 - 使用约束作为边,使用符号构建有向图。
- 对于图中的所有环,如果该环至少包含一条
<
边,则存在矛盾。
至query(X, Y)
:
X
找到和之间的任何路径Y
。- 如果没有这样的路径,这部分的结果是
{<, =, >}
。 - 如果路径至少包含一个
<
,则这部分的结果是{<}
. - 否则,这部分的结果是
{<, =}
。
- 如果没有这样的路径,这部分的结果是
Y
找到和之间的任何路径X
- 如果没有这样的路径,这部分的结果是
{<, =, >}
。 - 如果路径至少包含一个
<
,则这部分的结果是{>}
. - 否则,这部分的结果是
{=, >}
。
- 如果没有这样的路径,这部分的结果是
- 结果是上述两个结果的并集。
(显然,我可以缓存查询,至少在我添加另一个约束之前)
我可以将此扩展到包含!=
,但随后它会随着使用的约束数量成倍地变慢!=
。(保留一组图而不是一个。每次添加约束时!=
,对于集合中的每个图,将其替换为两个副本,一个要添加的约束是<
,一个是>
。任何时候都会产生矛盾,丢弃它。如果图集为空,则存在矛盾。在查询中,检查所有图,将答案合并在一起。)
那么,有没有更有效的方法来解决这个问题呢?还是无论如何都会成为指数级的最坏情况?
我知道我可以为此使用 SAT 求解器,但委婉地说,这似乎有点矫枉过正,特别是因为我看不到它超过 100 个约束,其中 10 个更典型。
(对于那些对此感兴趣的人,我正在研究一种玩具编程语言,并对制作自定义中缀运算符的想法感兴趣,其中优先级由与现有运算符的关系而不是直接数值决定(这有问题当您想添加一个优先级高于A
但低于的新运算符时B
,但两者之间没有差距。!=
该问题并不严格要求,但我开始对如何包含它感兴趣。)