CAD in Mathematica
今回は,Mathematica の CAD 関数についてのお話ですが,まずは用語の確認から,...,R^{n+1}(n≧1)の部分集合 X が Cylindrical であるとは,R^n の部分集合 Y と Y 上で定義された無限大を含めた実数値関数 f,g が存在して
X={(x_1,...,x_n,x_{n+1}) ; (x_1,...,x_n)∈Y ∧ f(x_1,...,x_n)≦または<x_{n+1}≦または<g(x_1,...,x_n) }
と表せることであり,R の部分集合 X が Cylindrical であるとは,X が R の区間であることでした.そして,R^n(n≧1)の部分集合 X を有限個の Cylindrical な集合,しかも,そこに現れる全ての Y も Cylindrical であり,以下同様であるように,分割したものを X の Cylindrical Decomposition と呼び,その f,g の全てが代数関数であるものを Cylindrical Algebraic Decomposition と呼ぶのでした.
さて,前回の Maple 上の CylindricalAlgebraicDecompose は,多項式のリストに対して,全空間を,そのリストの各多項式の符号を保つ Cylindrical な部分集合に分解する,いわゆる full CAD でしたが,Mathematica の CAD 関数 CylindricalDecomposition(CylindricalDecomposition—Wolfram Language Documentation)は,論理式のリストに対して,そのリストの各論理式の連言の解集合を,その連言の真理値を保つ Cylindrical な部分集合に分解する,いわゆる partial CAD です( QEPCAD B や RedLog の CAD もこれです).
使い方は簡単で
CylindricalDecomposition[ {論理式のリスト} , {自由変数,束縛変数のリスト} ]
と入力するだけで,その論理式の連言と等価な式を,Cylindrical な各集合を定める条件の選言として出力します.変数の消去(射影)は,リストで指定した右側の変数から順に実行されます.例えば
In[1]:= CylindricalDecomposition[ {a*x + b == 0}, {a, b, x} ]
Out[1]= (a < 0 && x == -(b/a)) ||
(a == 0 && b == 0) ||
(a > 0 && x == -(b/a))In[2]:= CylindricalDecomposition[ {a*x + b == 0}, {b, a, x} ]
Out[2]= (b < 0 && ( (a < 0 && x == -(b/a)) || (a > 0 && x == -(b/a)))) ||
(b == 0 && ( (a < 0 && x == 0) || a == 0 || (a > 0 && x == 0))) ||
(b >0 && ( (a < 0 && x == -(b/a)) || (a > 0 && x == -(b/a))))
といった具合です.
この CylindricalDecomposition の正式実装は Mathematica 5 ですが,Mathematica 6 において,指定した段階の射影や open CAD も出力できる GenericCylindricalDecomposition(http://reference.wolfram.com/mathematica/ref/GenericCylindricalDecomposition.ja.html)が追加されました.
その書式は
GenericCylindricalDecomposition[ {論理式のリスト} , {自由変数,束縛変数のリスト} , {自由変数,束縛変数のリスト} ]
であり,論理式に現れる変数は,第2,3引数のリストの少なくとも一方に属さねばなりません.まず,第2引数のリストが空ならば,出力は CylindricalDecomposition と同じです.逆に,第3引数のリストが空ならば,出力は
{ 解集合の内部の CAD , 解集合の境界の拡大集合の条件 }
であり,空ならそれぞれ False となります.このとき,入力された式を A,出力を { B , C } とおくと
¬C → ( A ←→ B )
が成り立っています.例えば,
In[3]:= CylindricalDecomposition[{x^2 + y^2 + z^2 <= 1}, {x, y, z}]
Out[3]= (x == -1 && y == 0 &&
z == 0) || (-1 < x <
1 && ( ( y == -Sqrt[1 - x^2] &&
z == -Sqrt[1 - x^2 - y^2]) || (-Sqrt[1 - x^2] < y < Sqrt[
1 - x^2] && -Sqrt[1 - x^2 - y^2] <= z <= Sqrt[
1 - x^2 - y^2]) || (y == Sqrt[1 - x^2] &&
z == -Sqrt[1 - x^2 - y^2]))) || (x == 1 && y == 0 && z == 0)In[4]:= GenericCylindricalDecomposition[{x^2 + y^2 + z^2 <=
1}, {}, {x, y, z}]Out[4]= (x == -1 && y == 0 &&
z == 0) || (-1 < x <
1 && ( ( y == -Sqrt[1 - x^2] &&
z == -Sqrt[1 - x^2 - y^2]) || (-Sqrt[1 - x^2] < y < Sqrt[
1 - x^2] && -Sqrt[1 - x^2 - y^2] <= z <= Sqrt[
1 - x^2 - y^2]) || (y == Sqrt[1 - x^2] &&
z == -Sqrt[1 - x^2 - y^2]))) || (x == 1 && y == 0 && z == 0)In[5]:= GenericCylindricalDecomposition[{x^2 + y^2 + z^2 <= 1}, {x,
y, z}, {}]Out[5]= {-1 < x < 1 && -Sqrt[1 - x^2] < y < Sqrt[
1 - x^2] && -Sqrt[1 - x^2 - y^2] < z < Sqrt[1 - x^2 - y^2], -1 +
x^2 + y^2 + z^2 == 0}In[6]:= GenericCylindricalDecomposition[{x^2 + y^2 + z^2 < 1}, {x,
y, z}, {}]Out[6]= {-1 < x < 1 && -Sqrt[1 - x^2] < y < Sqrt[
1 - x^2] && -Sqrt[1 - x^2 - y^2] < z < Sqrt[1 - x^2 - y^2],
False }In[7]:= GenericCylindricalDecomposition[{x^2 + y^2 + z^2 == 1}, {x,
y, z}, {}]Out[7]= { False, -1 + x^2 + y^2 + z^2 == 0 }
といった具合です.対外的には GenericCylindricalDecomposition は,その open CAD 出力を以って,CylindricalDecomposition の "内部による近似版","高速版" という位置付けのようで,確かに
In[8]:=
GenericCylindricalDecomposition[{x^2 + y^2 + z^2 < 1 &&
a*x + b*y + c*z > 1}, {a, b, c, x, y, z}, {}]; // TimingOut[8]= {0.796, Null}
ですが,CylindricalDecomposition は 1 時間以内には停止しませんので,体積や可視化などという恐ろしく贅沢な CAD の使い方にはピッタリなのかも知れません.
一方,本来の QE の立場から注目すべきは,何れの引数のリストも空でない入力に対する出力です.この場合の出力も 2 つの成分からなるリストですが,例えば
In[9]:= GenericCylindricalDecomposition[{x^2 + y^2 + z^2 <= 1},
{x, y}, {z}]Out[9]= {-1 < x < 1 && -Sqrt[1 - x^2] < y < Sqrt[
1 - x^2] && -Sqrt[1 - x^2 - y^2] <= z <= Sqrt[1 - x^2 - y^2],
1 + x == 0 || -1 + x == 0 || -1 + x^2 + y^2 == 0}
のように,{x,y},{z} なら y,x の評価が open,同様に {x},{y,z} なら x のみが open で評価されます.さらに
In[10]:= GenericCylindricalDecomposition[{x^2 + y^2 + z^2 <= 1},
{x, y}, {y, z}]Out[10]= {-1 < x < 1 && -Sqrt[1 - x^2 - y^2] <= z <= Sqrt[
1 - x^2 - y^2], -1 + x == 0 || 1 + x == 0}In[11]:= GenericCylindricalDecomposition[{x^2 + y^2 + z^2 <= 1},
{x, y}, {x, y, z}]Out[11]= {-Sqrt[1 - x^2 - y^2] <= z <= Sqrt[1 - x^2 - y^2], False}
In[12]:= GenericCylindricalDecomposition[{x^2 + y^2 + z^2 <= 1},
{z}, {x, y, z}]Out[12]= {(x == -1 &&
y == 0) || (-1 < x < 1 && -Sqrt[1 - x^2] <= y <= Sqrt[
1 - x^2]) || (x == 1 && y == 0), False}In[13]:= GenericCylindricalDecomposition[{x^2 + y^2 + z^2 <= 1},
{x, y, z}, {z}]Out[13]= {-1 < x < 1 && -Sqrt[1 - x^2] < y < Sqrt[1 - x^2],
1 + x == 0 || -1 + x == 0 || -1 + x^2 + y^2 == 0}
のようにすれば,2つのリストに共通に属する変数の評価が出力されません.従って,xy 空間への射影(つまり,z の消去)は {x, y}, {x, y, z},そこから x 空間への射影(つまり,z,y の消去)は {y, z}, {x, y, z} とすれば,それぞれ
In[14]:= GenericCylindricalDecomposition[{x^2 + y^2 + z^2 <= 1}, {x,
y}, {x, y, z}]Out[14]= {-Sqrt[1 - x^2 - y^2] <= z <= Sqrt[1 - x^2 - y^2], False}
In[15]:= GenericCylindricalDecomposition[{x^2 + y^2 + z^2 <= 1}, {y,
z}, {x, y, z}]Out[15]= {-1 <= x <= 1, False}
のように取り出せます.
なお,一連の関数の作者である Wolfram Research の Adam Strzebonski 氏が公開しておられる CAFView(http://members.wolfram.com/adams/Talks/Talk1007.nb)を用いると,CylindricalDecomposition の出力を
のように,セルの tree に対応した形で表示できます.