Logic 查找可能的布尔值以将表达式求值为true

Logic 查找可能的布尔值以将表达式求值为true,logic,expression,logical-operators,boolean-logic,boolean-expression,Logic,Expression,Logical Operators,Boolean Logic,Boolean Expression,如果我有一个给定的布尔表达式(和和或操作)和许多布尔变量,那么我想将这个表达式求值为true,如何找到所有可能的布尔值集来获得一个真正的表达式 例如,我有4个布尔变量a,b,c,d和一个表达式: (a ^ b) v (c ^ d) 我尝试过的最慢的方法是: 我构建一个表达式树来获取表达式中的所有变量,我得到一个{a,b,c,d}集 我找到集合的所有子集:{a}、{b}、{c}、{d}、{a,b}、{a,c}、{b,c}、{b,d}、{b,d}、{c,d}、{a,b,c}、{a,b,d}、{

如果我有一个给定的布尔表达式(
操作)和许多布尔变量,那么我想将这个表达式求值为true,如何找到所有可能的布尔值集来获得一个真正的表达式

例如,我有4个布尔变量
a
b
c
d
和一个表达式:

 (a ^ b) v (c ^ d)
我尝试过的最慢的方法是:

  • 我构建一个表达式树来获取表达式中的所有变量,我得到一个
    {a,b,c,d}
  • 我找到集合的所有子集:
    {a}、{b}、{c}、{d}、{a,b}、{a,c}、{b,c}、{b,d}、{b,d}、{c,d}、{a,b,c}、{a,b,d}、{a,c,d}、{a,c,d}、{a,b,c,d}
  • 对于每个子集,我将每个变量设置为true,然后计算表达式。如果表达式返回true,我将用值保存子集

EDIT:我消除了
NOT
操作符,使问题变得更简单。

我想我找到了一种不必尝试所有排列的计算方法,下面描述的我的高级大纲并不十分复杂。我将概述基本方法,您将自己完成两项后续任务:

  • 将逻辑表达式(如“a&&(B | | C)”解析为经典解析树,该解析树表示表达式,其中树中的每个节点要么是变量,要么是布尔运算,要么是“&&”、“| |”或“!”(NOT),其中两个子节点是其操作数。这是一个经典的解析树。谷歌上有很多这样做的例子

  • >将我的大纲翻译成实际C++代码。这也将取决于您,但我认为,一旦您将您的大脑集中在整体方法上,实现应该是相当明显的

为了解决这个问题,我将使用两阶段的方法

  • 我将使用的一般方法,以便列出布尔表达式将计算为
    true
    的所有变量的所有潜在值集的暂定列表

  • 在第二阶段,我将从所有可能的集合列表中删除那些逻辑上不可能的集合。这听起来可能令人困惑,因此我将首先解释第二阶段

  • 让我们使用以下数据类型。首先,我将使用布尔表达式计算为
    true
    false
    的可能值的数据类型:

    typedef std::set<std::pair<std::string, bool>> values_t;
    
    表示变量“a”的值为
    true
    。因此,这个
    std::set
    表示一组变量及其对应的值

    所有这些潜在的解决方案都将是:

    typedef std::list<values_t> all_values_t;
    

    在片场。这意味着为了使表达式的计算结果为
    true
    false
    ,“a”必须同时为true和false

    但这显然在逻辑上是不可能的。因此,在本解决方案的第2阶段,您需要简单地遍历
    所有
    值中的所有
    值,并删除包含某个变量的
    的“不可能”值。实现这一点的方法应该看起来相当明显,我不会浪费时间来描述它,但是一旦第1阶段完成,第2阶段应该很简单

    对于第1阶段,我们的目标是提出一个函数,大致如下所示:

    all_values_t phase1(expression_t expr, bool goal);
    
    expr
    是布尔表达式的解析表示形式,作为解析树(正如我在开头提到的,这部分由您决定)
    goal
    是您希望解析表达式的求值方式:
    phase1()
    返回所有可能的
    所有值,对于这些值,
    expr
    求值为
    true
    false
    ,如“goal”所示。显然,您将调用
    phase1()
    passing
    true
    以获取“目标”作为您的答案,因为这正是您想要了解的。但是
    phase1()
    将递归地调用自己,使用
    true
    false
    “目标”来实现它的魔力

    在继续之前,现在重要的是阅读和理解描述归纳法证明如何工作的各种资源。在你完全理解这个一般概念之前,不要再继续下去

    好了,现在你明白这个概念了。如果您这样做,那么您现在必须同意我的意见,即
    phase1()
    已经完成。它起作用了!归纳法证明首先假设
    phase1()
    做了它应该做的事情
    phase1()
    将对自身进行递归调用,由于
    phase1()
    返回正确的结果,
    phase1()
    可以简单地依靠自身来解决所有问题。看看这有多容易

    phase1()
    手头确实有一个“简单”的任务:

    • 检查解析树的顶级节点是什么。它将是变量节点或表达式节点(见上文)

    • 在此基础上返回相应的
      所有\u值\u t

    就这样。我们将采取两种可能性,一次一种

  • 顶层节点是一个变量
  • 因此,如果表达式只是一个变量,并且希望表达式返回
    goal
    ,则:

    values_t v{ {name, goal} };
    
    表达式计算为
    goal
    的方法只有一种:一种显而易见的简单方法:变量,以及
    goal
    的值

    只有一种可能的解决办法。没有其他选择:

    all_values_t res;
    
    res.push_back(v);
    
    return res;
    
    现在,另一种可能性是表达式中的顶级节点是布尔运算之一:and、or或not

    再一次,我们要分而治之,一次解决一个问题

    让我们说它不是。那我们该怎么办?这应该很容易:

    return phase1(child1, !goal);
    
    只需递归调用
    phase1()
    ,传递
    values_t v{ {name, goal} };
    
    all_values_t res;
    
    res.push_back(v);
    
    return res;
    
    return phase1(child1, !goal);
    
    all_values_t left_result=phase1(child1, true);
    
    all_values_t right_result=phase1(child2, true);