简化9变量布尔表达式

时间:2013-12-29 18:09:44

标签: boolean logic

我正在尝试创建一个井字游戏程序作为心理锻炼,我将董事会状态存储为像这样的布尔值:

http://i.imgur.com/xBiuoAO.png

我想简化这个布尔表达式......

(a&b&c) | (d&e&f) | (g&h&i) | (a&d&g) | (b&e&h) | (c&f&i) | (a&e&i) | (g&e&c)

我的第一个想法是使用Karnaugh Map,但没有在线求解器支持9个变量。

并提出问题:

首先,我如何知道布尔条件是否已经尽可能简单?

和第二:简化上述布尔条件是什么?

4 个答案:

答案 0 :(得分:5)

2。简化条件:

原始表达

a&b&c|d&e&f|g&h&i|a&d&g|b&e&h|c&f&i|a&e&i|g&e&c

可以简化为以下内容,知道&比|

更优先
e&(d&f|b&h|a&i|g&c)|a&(b&c|d&g)|i&(g&h|c&f)

短4个字符,在最差情况下执行18 &|评估(原始计数为23) 没有更短的布尔公式(见下文)。如果您switch to matrices,也许您可​​以找到另一种解决方案。

1。确保我们得到最小的公式

通常,很难找到最小的公式。如果您对此感兴趣,请参阅this recent paper。但在我们的案例中,有一个简单的证明。

对于公式大小,我们将推测公式为最小,对于布尔运算{{1},我们将对变量asize(a)=1进行推理},以及否定size(A&B) = size(A|B) = size(A) + 1 + size(B)(因此我们可以假设我们免费获得Negation Normal Form)。 就该尺寸而言,我们的配方尺寸为37。

你不能做得更好的证据在于首先要说明要检查8行,并且总是有一对字母区分2个不同的行。由于我们可以将这8个检查重新组合在不少于3个剩余变量的组合中,因此最终公式中的变量数量应至少为size(!A) = size(A),我们可以从中推导出最小树大小。

详细证明

让我们假设给定的公式8*2+3 = 19最小并且采用NNF格式。

  1. F不能包含F 等否定变量。为此,请注意!a应该单调,也就是说,如果它返回“true”(有一个获胜的行),则从F更改其中一个变量到false不应该改变那个结果。 According to Wikipediatrue可以不加否定地书写。更好的是,我们可以证明我们可以删除否定。在this answer之后,我们可以转换回DNF格式,删除中间的否定变量或将其替换为F

  2. true不能包含子树,如两个变量F 的分离。 要使此公式有用且无法与a|ba交换,则意味着存在相互矛盾的分配,例如 bF[a|b] = true,因此F[a] = falsea = false因为单调性。此外,在这种情况下,将b = true转为b会生成整个公式false,因为false。 因此,false = F[a] = F[a|false] >= F[a|b](b = false)之间有一行是事实的原因,它不能通过b,因此例如ae = true。 并且对该行的检查通过表达式h = true进行测试a|b。但是,这意味着当b为真且所有其他设置为false时,a,e,h仍然为真,这与公式的目的相矛盾。

  3. 每个看起来像F的子树都会检查一个唯一的行。所以最后一个字母应该出现在相应的分离a&b的正上方,或者这个叶子是无用的,可以安全地删除a或b。实际上,假设(a&b|...)&{c somewhere for sure here}没有出现在上面,游戏是c a&b&c,而所有其他变量都是true。然后c应该在上面的表达式返回false,因此false将始终无用。因此,删除a&b

  4. 会缩短表达式
  5. 有8个独立分支,因此至少有8个a&b类型的子树。我们无法使用2个连词的析取重新组合它们,因为a&baf从不共享相同的行,因此必须有3个外部变量。 h使最终公式中出现19个变量。 具有19个变量的树不能少于18个运算符,因此总大小必须至少为19 + 18 = 37。

  6. 您可以拥有上述公式的变体。

    QED。

答案 1 :(得分:0)

一种选择是手动执行卡诺图。由于你有9个变量,这就形成了一个2 ^ 4乘2 ^ 5的网格,这个网格相当大,而且通过等式的外观,可能也不是很有趣。

通过检查,它看起来不像卡诺图会给你任何有用的信息(卡诺图基本上将((!a)&b) | (a&b)等表达式简化为b),所以从简化的意义上说,表达式已经尽可能简单了。但是如果你想减少计算次数,你可以使用AND运算符在OR上的分布来分解一些变量。

答案 2 :(得分:0)

你知道,如果没有常见的子术语可以提取,那么这很简单(例如,如果你在两个不同的三重奏中有“a& b”)。

你知道你的tic tac toe解决方案必须已经尽可能简单,因为任何一对盒子最多只能属于一条获胜线(只有一条直线可以通过两个给定点),所以(a& b) )不能在你正在检查的任何其他胜利中重复使用。

(另外,“简单”可能意味着很多事情;指明你的意思可能会帮助你回答你自己的问题。)

答案 3 :(得分:0)

想到这一点的最佳方式是一个人如何看待它。没有人会对自己说“a和b和c,或者d和e和f,”等等。他们会说“连续三个,水平,垂直或对角线。”

此外,不是进行8次检查(3行,3列和2对角线),而是只进行4次检查(3行和1个对角线),然后将板旋转90度,然后再进行相同的检查。

这就是你最终的结果。这些函数都假设该板是一个三乘三的布尔矩阵,其中true表示获胜符号,false表示不赢的符号。

def win?(board)
  winning_row_or_diagonal?(board) ||
    winning_row_or_diagonal?(rotate_90(board))
end

def winning_row_or_diagonal?(board)
  winning_row?(board) || winning_diagonal?(board)
end

def winning_row?(board)
  3.times.any? do |row_number|
    three_in_a_row?(board, row_number, 0, 1, 0)
  end
end

def winning_diagonal?(board)
  three_in_a_row?(board, 0, 0, 1, 1)
end

def three_in_a_row?(board, x, y, delta_x, delta_y)
  3.times.all? do |i|
    board[x + i * delta_x][y + i * deltay]
  end
end

def rotate_90(board)
  board.transpose.map(&:reverse)
end

矩阵旋转来自此处:https://stackoverflow.com/a/3571501/238886

虽然这段代码相当冗长,但每个函数的意图都很明确。代码现在表达了tic-tac-toe的规则,而不是长的布尔表达式。