論理代数¶
本稿では SymPy が論理代数演算を実現するために用意しているモジュール
sympy.logic 配下を見ていく。 Python が組み込みで持っている論理演算を表現しなおした一連のクラス群などがある。
ブール論理クラス図¶
モジュール sympy.logic.boolalg に定義されているクラスの継承関係だけを図示するとこうなる。
クラス
BooleanのスーパークラスはクラスBasicである。このクラスが論理演算子&,|,~, etc. をオーバーロードしているので、オブジェクトA,Bがある要件を満たしていれば、例えばA & Bのような記法で論理式オブジェクトを生成できる。クラス
BooleanTrueとBooleanFalseはSingletonのサブクラスでもある。いつものようにオブジェクトSを用いて、それぞれのオブジェクトにアクセスできる。
クラス |
値 |
|---|---|
|
|
|
|
ブール関数オブジェクトはクラス
Booleanのサブクラスオブジェクトを木構造コンポジットで表現することになる。
ブール関数クラス¶
クラス BooleanFunction のサブクラスを表にまとめておく。いきなり直感的な操作ができると思う。
クラス |
演算子 |
演算の意味 |
|---|---|---|
And |
|
論理積、かつ、conjunction |
Or |
|
論理和、または、[inclusive] disjunction |
Not |
|
否定、でない、negation |
Xor |
|
排他的論理和、exclusive disjunction |
Nand |
n/a |
|
Nor |
n/a |
|
Implies |
|
ならば |
Equivalent |
n/a |
等値、equality? |
ITE |
n/a |
三項演算子のようなもの、conditioned disjunction |
論理演算の基本は &, |, ~ である。それぞれに対応するクラスが存在し、名前は And, Or, Not である。SymPy ではシンボルや論理式オブジェクトをこれらの組み合わせで組み立てることで表現する。
メソッド
as_setで具体的な集合オブジェクトを生成する。例えばAnd(-2 < x, x < 2).as_set()はInterval(-2, 2)を生成する。ここで
-2 < x等はまた別の型だが、今は気にしない。
論理式オブジェクトでもメソッド
subsを利用できる。オブジェクトを構成するシンボルに Python 組み込みのブーリアン値を代入するような使い方をする。S.trueとS.falseでも通じるはず。
関数¶
クラスのメソッドでないブール代数用関数を見ていく。
関数 SOPform, POSform¶
これらの関数は真理値表からブール関数オブジェクトを生成する。生成するブール関数オブジェクトは「最も単純化された表現」になっている。
SymPy では Sum of Products form と Product of Sums form を扱っている。
- 関数
SOPform(variables, minterms, dontcares=None) 戻り値は
Orオブジェクトである。- 関数
POSform(variables, minterms, dontcares=None) 戻り値は
Andオブジェクトである。
まずはテストコードを真似て動きを試してみる。
In [1]: SOPform('xyz', [[0, 0, 1], [0, 1, 1], [1, 0, 0], [1, 1, 0]])
Out[1]: Or(And(x, Not(z)), And(z, Not(x)))
In [2]: POSform('xyz', [[0, 0, 1], [0, 1, 1], [1, 0, 0], [1, 1, 0]])
Out[2]: And(Or(x, z), Or(Not(x), Not(z)))
真理値表 minterms はこのように入れ子の list で表現する。例えば
[0, 0, 1] の意図は「命題 ~x & ~y & z が真である」だ。
次に Wikipedia の例 を再現してみよう。ここでは引数 dontcare も指定する。
In [1]: %paste
minterms = [[0, 1, 0, 0],
[1, 0, 0, 0],
[1, 0, 0, 1],
[1, 0, 1, 0],
[1, 1, 0, 0],
[1, 1, 1, 1],]
dontcare = [[1, 0, 1, 1],
[1, 1, 1, 0],]
## -- End pasted text --
In [2]: SOPform('ABCD', minterms, dontcare)
Out[2]: Or(And(A, C), And(A, Not(B)), And(B, Not(C), Not(D)))
In [3]: POSform('ABCD', minterms, dontcare)
Out[3]: And(Or(A, B), Or(A, Not(C)), Or(C, Not(B), Not(D)))
当該記事の真理値表からこれらの関数の実引数を構成する方法を記す。
まず、当該記事の真理値表から
fが 0 の行はカットする。さらに
fが Don’t care な行はmintermsでは含めない。むしろdontcareの入れ子要素にする。
Out[2] が当該記事の最終結果と一致している。そして Out[2] と Out[3]
は等値だ。どうすればこのことが確認できるのか、わからないようなら考えて理解すること。
論理式を正規化する関数¶
忘れそうなので用語と関連する概念をまとめておく。
連言標準形 POS, CNF, Conjunctive Normal Form,
AND(...)選言標準形 SOP, DNF, Disjunctive Normal Form,
OR(...)
- 関数
to_cnf(expr, simplify=False),is_cnf(expr) 論理式オブジェクト
exprから、等値性を保ったまま「複数の論理和オブジェクトをオペランドとする一つの論理積オブジェクト」を生成する。In [1]: is_cnf(A & (B | (C & D))) Out[1]: False In [2]: to_cnf(A & (B | (C & D))) Out[2]: And(A, Or(B, C), Or(B, D))
- 関数
to_dnf(expr, simplify=False),is_dnf(expr) 論理式オブジェクト
exprから、等値性を保ったまま「複数の論理積オブジェクトをオペランドとする一つの論理和オブジェクト」を生成する。In [1]: is_dnf(A & (B | (C & D))) Out[1]: False In [2]: to_dnf(A & (B | (C & D))) Out[2]: Or(And(A, B), And(A, C, D))
- 関数
to_nnf(expr, simplify=False),is_nnf(expr) 論理式オブジェクト
exprから、等価性を保ったまま次の条件を満たす論理式オブジェクトを生成する。Notがかかるのが最も内側の論理式(おそらくシンボルだろう)だけであるそれを除けば、式を構成する演算子は
AndとOrだけである。
In [1]: is_nnf(A >> B) Out[1]: False In [2]: to_nnf(A >> B) Out[2]: Or(B, Not(A))
Warning
上記サンプルではあらかじめ下記のインポートが必要である。
>>> from sympy.logic.boolalg import (is_nnf, is_cnf, is_dnf)
単純化¶
- 関数
simplify_logic(expr, form=None, deep=True) この関数は論理式
exprを単純化したオブジェクトを生成する。キーワード引数
formに値を指定するならば、文字列cnfまたはdnfを与えること。その値に対応する形式の論理式オブジェクトが得られる。キーワード引数
deepは単純化の再帰をするかどうかを示すフラグ。
汎用の単純化関数 simplify も論理式オブジェクトを単純化するのに使える。
充足性テスト¶
モジュール sympy.logic.inference にはブール関数の充足性をテストする関数がある。
- 関数
satisfiable(expr, algorithm='dpll2', all_models=False) 論理式
exprの充足性をテストする。論理式
exprが真になる可能性が全くなければFalseを返す。論理式
exprが真になる可能性があれば、そのときのシンボルの組み合わせを一つ返す。In [1]: satisfiable((A | B) & (~A | ~B)) Out[1]: {B: False, A: True} In [2]: satisfiable((A & B) & (~A | ~B)) Out[2]: False
キーワード引数
all_models=Trueを指定すると、充足性可能のときのシンボルの組み合わせを全部返そうとする。さらに、この関数はジェネレーター化する。In [1]: list(satisfiable((A | B) & (~A | ~B), all_models=True)) Out[1]: [{B: False, A: True}, {B: True, A: False}]