nnscan

nns は最も外にある %and または %or に作用するのみなので

(%i1) nns(((x>=0)%and(x=0))%or((x>=1)%and(x=1)));
(%o1)         ((x = 0) %and (x >= 0)) %or ((x = 1) %and (x >= 1))
(%i2) nns((((x>=0)%and(x=0))%or((x>=1)%and(x=1)))%and((y>=0)%and(y=0)));
(%o2) (((x = 0) %and (x >= 0)) %or ((x = 1) %and (x >= 1))) %and (y = 0)

となってしまいます.

ということで,scanmap 版を作りました.

nns(f):=
block([cl,L,fk],cl(f,g):=length(f)<=length(g),
if atom(f) then return(f)
elseif op(f)="%and" then
 (L:sort(rest(full_listify(powerset(setify(args(f))))),cl), 
 for k:1 thru length(L) do
 (fk:substpart("%and",part(L,k),0),
 if qe([],(fk)%implies(f))=true then return(fk)))
elseif op(f)="%or" then
 (L:sort(rest(full_listify(powerset(setify(args(f))))),cl), 
 for k:1 thru length(L) do
 (fk:substpart("%or",part(L,k),0),
 if qe([],(f)%implies(fk))=true then return(fk)))
else f)$
nnscan(f):=scanmap(nns,f)$
(%i3) nnscan(%o1);
(%o3)                         (x = 0) %or (x = 1)
(%i4) nnscan(%o2);
(%o4)                 ((x = 0) %or (x = 1)) %and (y = 0)

scan ではなく,入力をまず連言or選言標準形に書き換えて nns するのが一般的でしょうが,果たして...