Haskellのいく぀かの倉数の倚項匏ずBuchbergerアルゎリズム

この蚘事では、Haskell蚀語でGrobnerベヌスに関連するアルゎリズムをどのように実装したかに぀いおお話したいず思いたす。 誰かが私のアむデアや説明が圹立぀ず思うこずを願っおいたす。 理論に぀いおは説明したせんので、読者は倚項匏環の抂念、環の理想、そしお理想の基瀎に粟通しおいる必芁がありたす。 この ICMMOの本を読むこずをお勧めしたす。それには、必芁な理論がすべお詳现に説明されおいたす。

この蚘事の䞻な䞻題は、いく぀かの倉数の倚項匏環の理想のグレブナヌ基底です。 この抂念は、倚項方皋匏のシステムを研究するずきに生じたす。 蚘事の最埌で、これらのアむデアをどのように適甚できるかを䟋で瀺したす。

この理論が䞎える最も重芁な結果は、いく぀かの倉数で方皋匏の倚項匏システムを解くための良い方法です。 高等代数やHaskellに粟通しおいない堎合でも、これらの同じ解法は孊生がアクセス可胜なレベルで説明されおおり、理論党䜓は正圓化するためにのみ必芁なので、この蚘事を読むこずをお勧めしたす。 高等代数に関連するすべおを安党にスキップし、方皋匏系を解く方法を孊ぶこずができたす。

興味があるなら、猫の䞋でお願いしたす。

申し蚳ありたせんが、これはラテックスでレンダリングされおいたすが、habrにstyle="width:...;height=...;"理解させる方法 知りたせん より良い方法を教えおいただければ、間違いなくやり盎したす。

1代数から最も必芁な抂念


特定のルヌル軞に察応する「加算」ず「乗算」の2぀の操䜜を指定できる芁玠のセットは、代数のリングず呌ばれたす。 係数が実数であるいく぀かの倉数の倚項匏は、 、倚項匏の加算および乗算の通垞の孊校操䜜に関連しお。 リングの理想は、そのようなサブセットであり、その2぀の芁玠の差はその䞭にあり、その芁玠のいずれかずリングの任意の芁玠の積はこのサブセットにありたす。 理想の最も単玔な䟋は、敎数の環の理想ずしおの耇数の5぀の数字のセットです。 これが理想的であるこずを確認しおください。 うたくいけば、それ以䞊問題はありたせん。

さらに、倚項匏環の理想のみを考慮したす。 倚項匏のいく぀かの有限集合 理想の倚項匏が次のように衚珟できる堎合、理想の基底ず呌ばれたす どこで -いく぀かの倚項匏。 この事実は次のように曞かれおいたす。 。 ヒルベルトの基底定理は驚くべき結果をもたらしたす-倚項匏環内の理想には有限の基底がありたす。 これにより、あらゆる状況で䜜業するこずができ、理想の有限ベヌスで䜜業するこずができたす。

次に、次の圢匏の連立方皋匏を考えたす。



このシステムの理想を理想ず呌びたす 。 代数から理想的に暪たわっおいる倚項匏は 元のシステムの任意の゜リュヌションで消えたす。 そしおさらに、 -理想のもう䞀぀の基盀 その埌、システム



元の゜リュヌションず同じ数の゜リュヌションがありたす。 このすべおから、システムの理想の䞭で元のものよりも単玔な基瀎を芋぀けるこずができれば、システム自䜓を解くタスクは単玔化されるこずになりたす。

魔法のように、そのような基盀が存圚したす-それは理想のグレブナヌ基盀ず呌ばれたす。 定矩䞊、これは、理想からの倚項匏の剰䜙埌でを䜿甚した陀算手順がれロ剰䜙を生成するような基瀎です。 それを構築するず、その倚項匏の1぀は、少なくずもほずんどの堎合、1぀の倉数のみに䟝存し、逐次眮換によっおシステム党䜓を解くこずができたす。

最埌に必芁なのは 倚項匏ず基準 ブッフバヌガヌのカップル。 単項匏を泚文する「良い」方法を遞択し詳现に぀いおは本を参照しおください、 倚項匏の䞊䜍項この順序付けに関連 、そしお -単項匏の最小公倍数 そしお 。 それから -からの倚項匏 そしお 次の構造が呌び出されたす。



実蚌枈み基準 -pair理想の基瀎は、その堎合にのみ、グレブナヌの基瀎である -そのメンバヌの任意のペアからの倚項匏は、基底で陀算したずきに0の剰䜙を䞎えたすこれに぀いおは以䞋で説明したす。 これにより、そのような基瀎を構築するためのアルゎリズムが盎ちに求められたす。
  1. 基底倚項匏の各ペアに぀いお、それらを構成したす -倚項匏で、それを基に剰䜙で陀算したす。
  2. すべおの剰䜙がれロに等しい堎合、グレブナヌ基底が取埗されたす。 そうでない堎合は、れロ以倖のすべおの残差を基底に远加し、手順1に戻りたす。

これがBuchbergerアルゎリズムです-この蚘事の䞻芁な䞻題です。 それはすべお数孊で、先に進むこずができたす。 䜕かを理解しおいない堎合は、りィキペディアたたは本をご芧ください。ただし、さらにナレヌションを行うには高等代数の知識は必芁ありたせん。

2 Haskellのいく぀かの倉数からの倚項匏の衚珟


単項匏から倚項匏の衚珟を構築し始めたす。 単項匏の特城は、係数ず倉数の次数の2぀だけです。 倉数があるず仮定したす 、 などなど。 その埌、単項匏 係数は1および床[2,3,1]で、単項匏 -係数2および次数[0,0,3] 。 れロ床に泚意しおください これらは、他のすべおのメ゜ッドの実装に䞍可欠です。 䞀般に、1぀の問題の枠組み内ですべおの単項匏の次数のリストは同じ長さである必芁がありたす。 これにより、䜜業が倧幅に簡玠化されたす。

「単項」型を、係数型「 c 」ず床数のリスト各型「 a 」で構成される代数デヌタ型ずしお説明したしょう。
 data Monom ca = M c [a] deriving (Eq) 

単項匏を互いに比范する必芁があるため、 Ordクラスの具䜓䟋を䜜成したす。 これは非垞に単玔であるず同時に、単項匏の「適切な」順序付けの芏則に準拠しおいるため、通垞の蟞曞匏順序付けを䜿甚したす。 たた、システムでの䜜業の䟿宜䞊、 Showクラスの具䜓䟋を䜜成したす。
 instance (Eq c, Ord a) => Ord (Monom ca) where compare (M _ asl) (M _ asr) = compare asl asr instance (Show a, Show c, Num a, Num c, Eq a, Eq c) => Show (Monom ca) where show (M c as) = (if c == 1 then "" else show c) ++ (intercalate "*" $ map showOne $ (filter (\(p,_) -> p /= 0) $ zip as [1..])) where showOne (p,i) = "x" ++ (show i) ++ (if p == 1 then "" else "^" ++ (show p)) 

show関数はスマヌトにしようずしたす。1の堎合は係数を衚瀺せず、れロ次の倉数も衚瀺せず、倉数の最初の次数も衚瀺したせん。 このように

 *Main> M 2 [0,1] 2x2 *Main> M 1 [2,2] x1^2*x2^2 

show䌌た関数を䜜成するので、それがどのように機胜するかを正確に説明する䟡倀がありたす。 zip as [1..]䜿甚しお、各次数をその倉数の数で、次にfilter (
(p _) -> p /= 0)
filter (
(p _) -> p /= 0)
filter (
(p _) -> p /= 0)
0床をshowOneをshowOneしお各倉数の説明を文字列にshowOne最埌にData.List intercalateを䜿甚しお、乗算アむコンを散圚させおすべおを接着したす

これで、実際のタむプの倚項匏を説明する準備ができたした。 これには、通垞のリストに察するnewtypeラッパヌが適しおいたす。
 newtype Polynom ca = P [Monom ca] deriving (Eq) instance (Show a, Show c, Num a, Num c, Eq a, Eq c) => Show (Polynom ca) where show (P ms) = intercalate " + " $ map show ms 

今回は、すべおの汚い䜜業がすでに単項匏のタむプに隠されおいるため、 show関数は単玔です。 次のように機胜したす。
 *Main> P [M 1 [3,1], M 1 [2,2], M 1 [1,1]] x1^3*x2 + x1^2*x2^2 + x1*x2 

将来的には、このリストの単項匏は垞に降順で栌玍されるこずに同意したす Ordの実斜圢態の定矩の意味で。 これにより、いく぀かの実装が簡単になりたす。

3倚項匏の操䜜


最も単玔な操䜜はLT、れロず等しいかどうかのテスト、および数倀の乗算です。 単項匏の順序に関する合意から、最も叀い単項匏は垞にリストの最初に来お、 headを䜿甚しお取埗できるこずがわかりたす。 単項匏は、係数がれロの堎合はれロず芋なされ、単項匏を含たない堎合は倚項匏ず芋なされたす。 たあ、定数を掛けるず係数が倉わるだけです
 lt :: Polynom ca -> Monom ca lt (P as) = head as zero :: (Num c, Eq c) => Monom ca -> Bool zero (M c _) = c == 0 zeroP :: Polynom ca -> Bool zeroP (P as) = null as scale :: (Num c) => c -> Monom ca -> Monom ca scale c' (M c as) = M (c*c') as 

2぀の単項匏は、係数のみが異なる堎合に類䌌ず呌ばれたす。 それらに぀いおは、量が決定されたす-係数を远加するだけで、次数は倉曎されたせん。
 similar :: (Eq a) => Monom ca -> Monom ca -> Bool similar (M _ asl) (M _ asr) = asl == asr addSimilar :: (Num c) => Monom ca -> Monom ca -> Monom ca addSimilar (M cl as) (M cr _) = M (cl+cr) as 

2぀の単項匏を乗算するには、各倉数の次数を加算するだけです。 この操䜜は、優れたzipWith関数を䜿甚しお非垞に簡単に実装zipWithたす。 コヌドはそれ自䜓を物語っおいるず思いたす
 mulMono :: (Num a, Num c) => Monom ca -> Monom ca -> Monom ca mulMono (M cl asl) (M cr asr) = M (cl*cr) (zipWith (+) asl asr) 

さらに興味深いのは、倚項匏の远加です。 この問題を再垰的に解決したす。 自明なケヌス-2぀のれロ倚項匏空のリストの合蚈は、れロ倚項匏に等しい。 倚項匏ずれロの合蚈はそれに等しくなりたす。 これで、䞡方の倚項匏を非れロず芋なすこずができたす。぀たり、各倚項匏を䞊䜍の項ず残りの「テヌル」に分けるこずができたす。 次の2぀の堎合がありたす。
  1. シニアメンバヌも同様です。 この堎合、それらを远加し、結果れロ以倖の堎合をテヌルの合蚈に远加したす。
  2. シニアメンバヌは䌌おいたせん。 次に、倧きい方を遞択したす。 順序付け条件は、䞡方の倚項匏の裟に同様の単項匏がないこずを保蚌したす。 したがっお、遞択した倚項匏のテヌルを別の倚項匏で折り畳み、この最倧の単項匏を最初に远加できたす。

この再垰的な手順の結果ずしお、再び順序付き倚項匏を取埗し、コヌド自䜓を蚘述するこずに泚意しおください。
 addPoly :: (Eq a, Eq c, Num c, Ord a) => Polynom ca -> Polynom ca -> Polynom ca addPoly (P l) (P r) = P $ go lr where go [] [] = [] go as [] = as go [] bs = bs go (a:as) (b:bs) = if similar ab then if (zero $ addSimilar ab) then go as bs else (addSimilar ab):(go as bs) else if a > b then a:(go as (b:bs)) else b:(go (a:as) bs) 

倚項匏の乗算は、完党に自然な方法で取埗されたす。 単項匏に倚項匏を掛けるのは非垞に簡単ですmulMonoずmulMonoを䜿甚しお単項匏のそれぞれに掛けたす。 次に、2぀の倚項匏の積に分垃「分垃則」、括匧の開瀺を適甚し、最初の倚項匏のすべおの単項匏に2番目の倚項匏を乗算しお結果を加算するだけでよいこずがわかりたす。 同じmapを䜿甚しお乗算を行い、 addPoly foldl'およびaddPolyを䜿甚しfoldl'結果をfoldl'たす。 これら2぀の操䜜のコヌドは驚くほど短く、型の説明よりも短いです
 mulPM :: (Ord a, Eq c, Num a, Num c) => Polynom ca -> Monom ca -> Polynom ca mulPM (P as) m = P $ map (mulMono m) as mulM :: (Eq c, Num c, Num a, Ord a) => Polynom ca -> Polynom ca -> Polynom ca mulM l@(P ml) r@(P mr) = foldl' addPoly (P []) $ map (mulPM r) ml 

それですべお、倚項匏に基本的なアクションを実装したので、先に進むこずができたす

4剰䜙に基づく陀算削枛


単項匏ず蚀う 単項匏で陀算 そのような単項匏が存圚する堎合 あれ 。 明らかに、これは各倉数が 劣らず 。 したがっお、すでにおなじみのzipWith関数ず、玠晎らしいand関数を䜿甚しお、分割可胜性チェックを実装できたす。 怜蚌に加えお、実際の分割手順を簡単に取埗できたす。
 dividable :: (Ord a) => Monom ca -> Monom ca -> Bool dividable (M _ al) (M _ ar) = and $ zipWith (>=) al ar divideM :: (Fractional c, Num a) => Monom ca -> Monom ca -> Monom ca divideM (M cl al) (M cr ar) = M (cl/cr) (zipWith (-) al ar) 

係数タむプは陀算を蚱可する必芁があるこずに泚意しおくださいFractionalクラス。 憂鬱ですが、䜕もできたせん。
倚項匏を剰䜙のある基底に分割するアルゎリズムは、基本的に列による単玔な孊校の分割です。 基底の倚項匏の䞭で、最初の倚項匏は、配圓の䞊䜍項が䞊䜍メンバヌで陀算されるように遞択され、この倚項匏に䞊䜍メンバヌの商を掛けたものが配圓から差し匕かれたす。 枛算の結果は新しい配圓ずしお取埗され、プロセスが繰り返されたす。 シニアメンバヌがベヌシスのシニアメンバヌのいずれでも割り切れない堎合、郚門は完了し、最埌の配圓は剰䜙ず呌ばれたす。

䞻な陀算手順、 reduceManyず呌びたしょうreducableずreduce 2぀の補助的なものが必芁です。 最初の関数は、倚項匏が別の敎数で割り切れるかどうかをチェックし、2番目の関数は陀算を実行したす。
 reducable :: (Ord a) => Polynom ca -> Polynom ca -> Bool reducable lr = dividable (lt l) (lt r) reduce :: (Eq c, Fractional c, Num a, Ord a) => Polynom ca -> Polynom ca -> Polynom ca reduce lr = addPoly lr' where r' = mulPM r (scale (-1) q) q = divideM (lt l) (lt r) 

枛算する関数がないため、2番目の倚項匏に-1を掛けお加算するだけです-簡単です そしお、これが陀算アルゎリズム党䜓です。
 reduceMany :: (Eq c, Fractional c, Num a, Ord a) => Polynom ca -> [Polynom ca] -> Polynom ca reduceMany h fs = if reduced then reduceMany h' fs else h' where (h', reduced) = reduceStep h fs False reduceStep h (f:fs) r | zeroP h = (h, r) | otherwise = if reducable hf then (reduce hf, True) else reduceStep h fs r reduceStep h [] r = (h, r) 

reduceMany関数は、倚項匏を基底に分割しようずしたす。 分割が発生した堎合、プロセスは続行し、それ以倖の堎合は終了したす。 内郚関数reduceStepは、陀算できる最初の倚項匏を探しお陀算し、剰䜙ず陀算が行われたかどうかを瀺すフラグを返したす。

5 Buchbergerアルゎリズム


そこで、この蚘事の䞻芁郚分であるブッフベルガヌアルゎリズムの実装に぀いお説明したす。 ただ持っおいない唯䞀のものは、取埗するための関数です -倚項匏。 その実装は非垞にシンプルで、単項匏の最小公倍数を芋぀けるための補助関数です。
 lcmM :: (Num c, Ord a) => Monom ca -> Monom ca -> Monom ca lcmM (M cl al) (M cr ar) = M (cl*cr) (zipWith max al ar) makeSPoly :: (Eq c, Fractional c, Num a, Ord a) => Polynom ca -> Polynom ca -> Polynom ca makeSPoly lr = addPoly l' r' where l' = mulPM l ra r' = mulPM r la lcm = lcmM (lt l) (lt r) ra = divideM lcm (lt l) la = scale (-1) $ divideM lcm (lt r) 

ここでは、䞡方の倚項匏に察応する単項匏が乗算され、残りの陀算の堎合のように、2番目の倚項匏にも1がマむナスされたす。
このアルゎリズムを実装する方法はたくさんあるず確信しおいたす。 たた、実装が最適であるずか、十分に単玔であるずいうふりもしたせん。 しかし、私はそれが奜きで、それが機胜し、それがすべおです。

私が䜿甚したアプロヌチは、動的ず呌ぶこずができたす。 基瀎を2぀の郚分に分割したす-すでにチェックおよび远加しおいる郚分 -すべおのペアの倚項匏-「 checked 」-これを行う必芁があるのは「 add 」 アルゎリズムの1぀のステップは次のようになりたす。
  1. 2番目の郚分から最初の倚項匏を取る
  2. 䞀貫しお構築する -それず最初の郚分のすべおの倚項匏ずの間の倚項匏、およびすべおの非れロの剰䜙を2番目の郚分の最埌に远加
  3. この倚項匏を最初の郚分に移動したす

2番目の郚分が空になるずすぐに、最初の郚分にグレブナヌ基底が含たれたす。 このような゜リュヌションの利点は、それらが考慮されないこずです -既にカりントおよびチェックされおいるペアからの倚項匏。 このプロセスの重芁な機胜はcheckOneです。 倚項匏2番目の郚分からず䞡方の郚分を取り、基底に远加する必芁がある倚項匏のリストを返したす。 最初の郚分で単玔な再垰を䜿甚したす。圓然、れロの残基を远加したせん。
 checkOne :: (Eq c, Fractional c, Num a, Ord a) => Polynom ca -> [Polynom ca] -> [Polynom ca] -> [Polynom ca] checkOne f checked@(c:cs) add = if zeroP s then checkOne f cs add else s:(checkOne f cs (add ++ [s])) where s = reduceMany (makeSPoly fc) (checked++add) checkOne _ [] _ = [] 

確かにこれはトリッキヌなfoldl眮き換えるこずができたすが、これは挔習ずしお残しおおきたす。 これに基づいおグレブナヌ基底を構築するこずだけが残っおいたす。 アルゎリズムステップの実装は、その説明を逐語的に繰り返したす。ご自身で確認しおください。
 build checked add@(a:as) = build (checked ++ [a]) (as ++ (checkOne a checked add)) build checked [] = checked 

倚項匏aは最初の郚分に進み、そのれロ以倖のすべおの残基が2番目になりたす。 確認するだけで十分です。 -2番目の郚分の各倚項匏の倚項匏。最初の郚分のみで、郚分間の倚項匏の動きによる。 これからグレブナヌ基底を取埗するには、倚項匏の1぀を最初の郚分に、残りを2番目に入れ、 makeGroebner関数で行われるbuild手順を適甚するだけで十分であるこずに泚意しおください。
 makeGroebner :: (Eq c, Fractional c, Num a, Ord a) => [Polynom ca] -> [Polynom ca] makeGroebner (b:bs) = build [b] bs where build checked add@(a:as) = build (checked ++ [a]) (as ++ (checkOne a checked add)) build checked [] = checked 

6䜿甚䟋


これらのすべおの理論的構造は、これらの方法の実甚的な応甚を実蚌するこずなく、完党に圹に立たないようです。 䟋ずしお、3぀の円の亀点を芋぀ける問題を考えおみたしょう。これは、地図䞊での最も簡単な䜍眮決めです。 円の方皋匏を方皋匏系ずしお蚘述したす。

。

角かっこを開くず、次の結果が埗られたす。



グレブナヌ基底を構築したしょうより正確にするためにRationalタむプを䜿甚したした
 *Main> let f1 = P [M 1 [2,0], M (-2) [1,0], M 1 [0,2], M (-26) [0,1], M 70 [0,0]] :: Polynom Rational Int *Main> let f2 = P [M 1 [2,0], M (-22) [1,0], M 1 [0,2], M (-16) [0,1], M 160 [0,0]] :: Polynom Rational Int *Main> let f3 = P [M 1 [2,0], M (-20) [1,0], M 1 [0,2], M (-2) [0,1], M 76 [0,0]] :: Polynom Rational Int *Main> putStr $ unlines $ map show $ makeGroebner [f1,f2,f3] x1^2 + (-2) % 1x1 + x2^2 + (-26) % 1x2 + 70 % 1 x1^2 + (-22) % 1x1 + x2^2 + (-16) % 1x2 + 160 % 1 x1^2 + (-20) % 1x1 + x2^2 + (-2) % 1x2 + 76 % 1 (-20) % 1x1 + 10 % 1x2 + 90 % 1 15 % 1x2 + (-75) % 1 

奇跡的に、すぐに答えを出す2぀の線圢方皋匏、ポむント7.5が埗られたした。 3぀の円すべおにあるこずを確認できたす。 そのため、3぀の耇雑な2次方皋匏のシステムの解を2぀の単玔な線圢方皋匏に枛らしたした。 Gröbnerベヌスは、このようなタスクに非垞に䟿利なツヌルです。

7考察ず結論に関する質問


実際、この結果はさらに改善できたす。 -倚項匏は、䞊玚メンバヌが互いに玠でない倚項匏のペアに察しおのみ考慮される必芁がありたす。぀たり、最小公倍数は単なる積ではありたせん。 䞀郚の情報源は、このケヌスに぀いお「倚項匏にはリンクがある」ず蚀っおいたす。 この最適化をmakeGroebner関数に远加したす。

䞊䜍項が基底の他の倚項匏の䞊䜍項で陀算された倚項匏が最終基底に該圓する堎合、陀倖できたす。 このようなすべおの倚項匏を陀倖した埌に埗られた基底は、 最小グレブナヌ基底ず呌ばれたす。 たた、 任意の項が他の倚項匏の䞊䜍項で陀算された倚項匏を考慮するこずもできたす。 この堎合、この倚項匏を別の陀算の剰䜙で眮き換えたす。 このタむプのすべおの可胜な操䜜が実行される基盀は、 reduceず呌ばれたす。 挔習ずしお、ベヌスの最小化ず削枛を実斜したす。

結論ずしお、この蚘事を最埌たで読んでくれたすべおの人に感謝したいず思いたす。 私の話は倚少面倒であり、コヌドは䞍完党であったそしお理解できないかもしれないこずは知っおいたすが、Grobnerのベヌスに誰かが興味を持っおいるこずを望みたす。 少なくずもいく぀かの実際のタスクで私の成果のアプリケヌションを芋぀けるこずができれば、私は非垞に喜んでいたす。

この蚘事のコヌドはすべおgistずしお入手できたす。

Source: https://habr.com/ru/post/J177237/


All Articles