什么是最好的(在简单的使用和性能方面)C ++ / C ++ 11库可以简化如下的公式?
(a < 0 && b > 0) || (a < 0 && c > 0) || (a < 0 && c > 1)
到(例如)
a < 0 && (b > 0 || c > 0)
我认为解释一件事非常重要(因为我看到这个问题被误解了)。
我不想简化C / C ++表达式 - 我知道,编译器可以实现它。
我正在制作图形处理工具。在图的边缘,有一些关于其顶点的条件(假设顶点是a
,b
,c
,这些条件类似于a<b
,{{ 1}}等 - 请注意,这些条件不表示为“字符串”,它们可以是任何函数或库调用)。在处理过程中,我一起收集表达式,在进一步的图形处理之前,我想简化它们。
将在运行时创建条件和表达式。
我希望能够向该库输入一些表达式,例如:
b>0
当然这个库可能会有更多漂亮的API。我把它写成方法调用只是为了展示我期望的底层机制 - 强调一点,我不需要源代码编译器,或者这个问题与源代码编译优化无关。
答案 0 :(得分:8)
您正在寻找可以处理布尔逻辑的C ++符号数学库。
以下是一些入门:
答案 1 :(得分:6)
如果你第一次生成真值表(相当简单),这会减少到经过充分研究的circuit minimization problem,。
答案 2 :(得分:6)
代替专用库,我建议的解决问题的程序如下:
假设您的给定用例完全代表问题空间,那么您可以使用任何支持真值表输入和“不关心”(DNC)函数输出规范的布尔表达式简化器。 DNC之所以重要,是因为某些单变量比较表达式可能意味着同一变量的其他比较表达式。考虑以下单变量比较表达式到布尔变量映射:
A = (a < 0); B = (b > 0); C = (c > 0); D = (c > 1);
D暗示C或等效(不是D或C)始终为真。因此,在考虑示例表达式的输入时(替换我们新定义的布尔变量)
Output = (A && B) || (A && C) || (A && D)
当(不是D或C)为假时,我们不关心此表达式的输入,也不关心此表达式的输出,因为它永远不会发生。我们可以通过生成上述表达式的真值表来利用这一事实,并在(非D或C)为假的情况下将所需的输出标记为DNC。从该真值表中,您可以使用布尔表达式简化器来生成简化表达式。
让我们将该过程应用于您的示例,假设单变量比较表达式给出上面给出的布尔变量映射。特别是,我们有
Output = (A && B) || (A && C) || (A && D)
映射到下面的真值表。但是,从你的例子中,我们知道(不是D或C)总是如此;因此,我们可以将所有输出标记为(D而不是C)作为DNC,这将导致下面的真值表II。
Truth Table I Truth Table II
============= ==============
A B C D Output A B C D Output
0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 1 DNC
0 0 1 0 0 0 0 1 0 0
0 0 1 1 0 0 0 1 1 0
0 1 0 0 0 0 1 0 0 0
0 1 0 1 0 0 1 0 1 DNC
0 1 1 0 0 0 1 1 0 0
0 1 1 1 0 0 1 1 1 0
1 0 0 0 0 1 0 0 0 0
1 0 0 1 1 1 0 0 1 DNC
1 0 1 0 1 1 0 1 0 1
1 0 1 1 1 1 0 1 1 1
1 1 0 0 1 1 1 0 0 1
1 1 0 1 1 1 1 0 1 DNC
1 1 1 0 1 1 1 1 0 1
1 1 1 1 1 1 1 1 1 1
将真值表II插入Logic Friday并使用其求解器产生最小化(CNF)表达式:
A && (B || C)
或等效地,从布尔变量映射回来,
a < 0 && (b > 0 || c > 0).
答案 3 :(得分:2)
我建议你建立一个决策树。
您的每个条件将数字空间分为两个部分。例如,c > 1
将空格划分为(-Infinity, 1]
和[1, +Infinity)
部分。如果您有c
的其他条件,例如c>0
,那么您有额外的分割点0
,最后您会获得3个部分:(-Infinity, 0]
,[0,1]
和{{ 1}}。
因此,每个树级别都包含适当的分支:
[1, +Infinity)
现在您应该只保留表达式中存在的路径。这将是您的优化。不确定它是100%有效,但它在某种程度上有效。
在你的情况下,它将是
c<0
b<0
a<0
a>0
b>0
a<0
a>0
0<c<1
b<0
a<0
a>0
b>0
a<0
a>0
c>1
b<0
a<0
a>0
b>0
a<0
a>0
为了改进优化,您可以将子树比较和联合等效子树引入一个
c<0
b<0: false
b>0
a<0: true
a>0: false
0<c<1
b<0
a<0: true
a>0: false
b>0
a<0: true
a>0: false
c>1
b<0
a<0: true
a>0: false
b>0
a<0: true
a>0: false
最后,当您收到您的值时,只需跟踪树并检查您的决定。如果你得到一个死胡同(删除的路径),那么结果是c<0
b<0: false
b>0
a<0: true
a>0: false
c>0
a<0: true
a>0: false
。否则,您将跟踪退出,结果将为false
。
答案 4 :(得分:-1)
您或许可以从BDD库中获得所需内容。 BDD最后并没有给你一个C ++表达式,但它们为你提供了一个图表,你可以用它来构造一个C ++表达式。
我从未使用它,但我听说minidd很容易使用。见http://www.cprover.org/miniBDD/
答案 5 :(得分:-2)
简化表达式的最佳工具是编译器的优化器。
据我所知,没有c ++库会为你重写这样的表达式(尽管从技术上讲,使用表达式模板编写一个表达式是可行的)。
我建议您查看编译器使用高优化生成的汇编代码。它可能会给你一个提示。静态分析工具提供了另一种替代方案。