dnf と cnf(nnsolve その2)

選言標準形,連言標準形は代数で言えば,それぞれ展開,因数分解に当たる基本的なものであり,前者は所謂(排他的とは限らない)場合分けなので,方程式系の解の構成には欠かせません.

その実装は簡単で,例えば,A ∧ (B ∨ C) を (A ∧ B) ∨ (A ∧ C) に可能な限り置き換えれば良いだけです.

が,...それは連言,選言が 2 項オペレーターの場合の話.%and,%or は nary なので,そのままではパターンにマッチしません.

というわけで,作ったのが以下の dnf と cnf です.

infix(Or,60,40)$
infix(And,60,40)$

/* n項 %and,%or を2項 And,Or の合成に */
orand2orand(f):=block([g],g:f,
if atom(g) then return(g),
if op(g)="%or" then g:xreduce("Or",args(g)),
if op(g)="%and" then g:xreduce("And",args(g)),g)$

/* 分配 */
matchdeclare([aa,bb,cc],true)$
defrule(ru05r, (aa) Or ((bb) And (cc)), ((aa) Or (bb)) And ((aa) Or (cc)))$
defrule(ru08r, ((bb) And (cc)) Or (aa), ((aa) Or (bb)) And ((aa) Or (cc)))$
defrule(ru05a, (aa) And ((bb) Or (cc)), ((aa) And (bb)) Or ((aa) And (cc)))$
defrule(ru08a, ((bb) Or (cc)) And (aa), ((aa) And (bb)) Or ((aa) And (cc)))$

/* subst の並列でも可 */
defrule(ru00r, (aa) Or (bb), (aa) %or (bb))$
defrule(ru00a, (aa) And (bb), (aa) %and (bb))$

cnf(f):=applyb2(applyb2(scanmap(orand2orand,f),ru05r,ru08r),ru00r,ru00a)$
dnf(f):=applyb2(applyb2(scanmap(orand2orand,f),ru05a,ru08a),ru00r,ru00a)$

実行例

Maxima 5.36.1 http://maxima.sourceforge.net
using Lisp CMU Common Lisp 20d (20D Unicode)
Distributed under the GNU Public License. See the file COPYING.
Dedicated to the memory of William Schelter.
The function bug_report() provides bug reporting information.
(%i1) (x=0)%or((x-1=0)%and(y=0)%and(z=0));
(%o1)         (x = 0) %or ((x - 1 = 0) %and (y = 0) %and (z = 0))
(%i2) cnf(%);
(%o2) ((x - 1 = 0) %or (x = 0)) %and ((x = 0) %or (y = 0))
                                                     %and ((x = 0) %or (z = 0))
(%i3) dnf(%);
(%o3) (x = 0) %or ((x - 1 = 0) %and (x = 0))
 %or ((x - 1 = 0) %and (x = 0) %and (y = 0))
 %or ((x - 1 = 0) %and (x = 0) %and (z = 0))
 %or ((x - 1 = 0) %and (y = 0) %and (z = 0)) %or ((x = 0) %and (y = 0))
 %or ((x = 0) %and (y = 0) %and (z = 0)) %or ((x = 0) %and (z = 0))
(%i4) cnf(%);
(%o4) ((x - 1 = 0) %or (x = 0)) %and ((x - 1 = 0) %or (x = 0) %or (y = 0))
 %and ((x - 1 = 0) %or (x = 0) %or (y = 0) %or (z = 0))
 %and ((x - 1 = 0) %or (x = 0) %or (z = 0)) %and ((x = 0) %or (y = 0))
 %and ((x = 0) %or (y = 0) %or (z = 0)) %and ((x = 0) %or (z = 0))
(%i5) dnf(%);
(%o5) (x = 0) %or ((x - 1 = 0) %and (x = 0))
 %or ((x - 1 = 0) %and (x = 0) %and (y = 0))
 %or ((x - 1 = 0) %and (x = 0) %and (y = 0) %and (z = 0))
 %or ((x - 1 = 0) %and (x = 0) %and (z = 0))
 %or ((x - 1 = 0) %and (y = 0) %and (z = 0)) %or ((x = 0) %and (y = 0))
 %or ((x = 0) %and (y = 0) %and (z = 0)) %or ((x = 0) %and (z = 0))
(%i6) cnf(%);
(%o6) ((x - 1 = 0) %or (x = 0)) %and ((x - 1 = 0) %or (x = 0) %or (y = 0))
 %and ((x - 1 = 0) %or (x = 0) %or (y = 0) %or (z = 0))
 %and ((x - 1 = 0) %or (x = 0) %or (z = 0)) %and ((x = 0) %or (y = 0))
 %and ((x = 0) %or (y = 0) %or (z = 0)) %and ((x = 0) %or (z = 0))
(%i7) nns(qe([],%));
(%o7)         (x = 0) %or ((x - 1 = 0) %and (y = 0) %and (z = 0))