オオカミずダギずキャベツの問題を䟋にした圢匏的怜蚌

私の意芋では、むンタヌネットのロシア語分野では、圢匏的怜蚌のテヌマが十分にカバヌされおおらず、特に単玔か぀明確な䟋が䞍足しおいたす。

倖囜の情報源からの䟋を挙げ、オオカミ、ダギ、キャベツを川の向こう岞に枡るずいうよく知られた問題に私なりの解決策を加えたす。

その前に、正匏な怜蚌ずは䜕か、そしおなぜそれが必芁なのかに぀いお簡単に説明したす。

正匏な怜蚌は通垞、あるプログラムたたはアルゎリズムを別のプログラムたたはアルゎリズムを䜿甚しおチェックするこずを意味したす。

これは、プログラムが期埅どおりに動䜜するこずを保蚌し、たたそのセキュリティを確保するために必芁です。

正匏怜蚌は、脆匱性を発芋しお排陀するための最も匷力な手段です。これにより、プログラムに存圚するすべおのホヌルやバグを芋぀けたり、それらが存圚しないこずを蚌明したりするこずができたす。
ボヌド幅 8 マスの 1000 クむヌンの問題など、堎合によっおはこれが䞍可胜であるこずに泚意しおください。すべおはアルゎリズムの耇雑さたたは停止問題に垰着したす。

ただし、いずれの堎合も、プログラムが正しい、間違っおいる、たたは答えを蚈算できなかったずいう XNUMX ぀の答えのうち XNUMX ぀が返されたす。

答えを芋぀けるこずができない堎合は、倚くの堎合、特定の「はい」たたは「いいえ」の答えを埗るために、プログラムの䞍明確な郚分を再加工しおアルゎリズムの耇雑さを軜枛するこずが可胜です。

たた、最倧レベルの保護を確保するために、Windows カヌネルや Darpa ドロヌン オペレヌティング システムなどで正匏な怜蚌が䜿甚されたす。

自動定理蚌明ず方皋匏解決のための非垞に匷力なツヌルである Z3Prover を䜿甚したす。

さらに、Z3 は方皋匏を解き、力ずくで倀を遞択したせん。
これは、入力オプションの組み合わせが 10^100 通りある堎合でも、答えを芋぀けるこずができるこずを意味したす。

ただし、これは Integer 型の入力匕数が玄 XNUMX 個だけであり、実際にはよく発生したす。

8 クむヌンに関する問題 (英語から抜粋) マニュアル).

オオカミずダギずキャベツの問題を䟋にした圢匏的怜蚌

# We know each queen must be in a different row.
# So, we represent each queen by a single integer: the column position
Q = [ Int('Q_%i' % (i + 1)) for i in range(8) ]

# Each queen is in a column {1, ... 8 }
val_c = [ And(1 <= Q[i], Q[i] <= 8) for i in range(8) ]

# At most one queen per column
col_c = [ Distinct(Q) ]

# Diagonal constraint
diag_c = [ If(i == j,
              True,
              And(Q[i] - Q[j] != i - j, Q[i] - Q[j] != j - i))
           for i in range(8) for j in range(i) ]

solve(val_c + col_c + diag_c)

Z3 を実行するず、次の解決策が埗られたす。

[Q_5 = 1,
 Q_8 = 7,
 Q_3 = 8,
 Q_2 = 2,
 Q_6 = 3,
 Q_4 = 6,
 Q_7 = 5,
 Q_1 = 4]

クむヌン問題は、8 ぀のクむヌンの座暙を入力ずしお受け取り、クむヌンが互いに勝぀かどうかの答えを出力するプログラムに盞圓したす。

このようなプログラムを圢匏的怜蚌を䜿甚しお解決する堎合、問題ず比范するず、プログラム コヌドを方皋匏に倉換するずいう圢でもう XNUMX ぀の手順を実行するだけで枈みたす。぀たり、それは本質的に私たちのものず同じであるこずがわかりたす (もちろん、プログラムが正しく曞かれおいればの話ですが)。

脆匱性の怜玢の堎合もほが同じこずが起こりたす。必芁な出力条件 (管理者パスワヌドなど) を蚭定し、゜ヌスたたは逆コンパむルされたコヌドを怜蚌に適合する匏に倉換するだけで、結果が䜕であるかに぀いおの答えが埗られたす。目暙を達成するには、デヌタを入力ずしお提䟛する必芁がありたす。

私の意芋では、オオカミ、ダギ、キャベツの問題はさらに興味深いものです。なぜなら、それを解くにはすでに倚くの (7) ステップが必芁だからです。

クむヌンの問題が、単䞀の GET たたは POST リク゚ストを䜿甚しおサヌバヌに䟵入できる堎合に匹敵する堎合、オオカミ、ダギ、キャベツは、より耇雑で広範なカテゎリの䟋を瀺しおおり、その䞭でのみ目暙を達成できたす。いく぀かのリク゚ストにより。

これは、たずえば、SQL むンゞェクションを芋぀けお、それを介しおファむルを曞き蟌み、暩限を昇栌しおからパスワヌドを取埗する必芁があるシナリオに盞圓したす。

問題の状況ずその解決策蟲倫はオオカミ、ダギ、キャベツを川を枡っお運ぶ必芁がありたす。 蟲堎䞻は、蟲堎䞻自身の他に、XNUMX ぀のオブゞェクトのみを収容できるボヌトを持っおいたす。 蟲倫が攟っおおくずオオカミがダギを食べ、ダギがキャベツを食べおしたいたす。

解決策は、ステップ 4 で蟲家がダギを取り戻す必芁があるこずです。
では、プログラムで解決しおみたしょう。

蟲倫、オオカミ、ダギ、キャベツを、4 たたは 0 の倀のみを取る 1 ぀の倉数ずしお衚したす。XNUMX はそれらが巊岞にあるこずを意味し、XNUMX はそれらが右岞にあるこずを意味したす。

import json
from z3 import *
s = Solver()
Num= 8

Human = [ Int('Human_%i' % (i + 1)) for i in range(Num) ]
Wolf = [ Int('Wolf_%i' % (i + 1)) for i in range(Num) ]
Goat = [ Int('Goat_%i' % (i + 1)) for i in range(Num) ]
Cabbage = [ Int('Cabbage_%i' % (i + 1)) for i in range(Num) ]

# Each creature can be only on left (0) or right side (1) on every state
HumanSide = [ Or(Human[i] == 0, Human[i] == 1) for i in range(Num) ]
WolfSide = [ Or(Wolf[i] == 0, Wolf[i] == 1) for i in range(Num) ]
GoatSide = [ Or(Goat[i] == 0, Goat[i] == 1) for i in range(Num) ]
CabbageSide = [ Or(Cabbage[i] == 0, Cabbage[i] == 1) for i in range(Num) ]
Side = HumanSide+WolfSide+GoatSide+CabbageSide

Num は、解決するために必芁なステップ数です。 各ステップは、川、ボヌト、およびすべおの゚ンティティの状態を衚したす。

ずりあえずランダムに遞んで䜙裕を持っお10個取りたしょう。

各゚ンティティは 10 個のコピヌで衚されたす。これは 10 個の各ステップでの倀です。

次に、開始ず終了の条件を蚭定したしょう。

Start = [ Human[0] == 0, Wolf[0] == 0, Goat[0] == 0, Cabbage[0] == 0 ]
Finish = [ Human[9] == 1, Wolf[9] == 1, Goat[9] == 1, Cabbage[9] == 1 ]

次に、オオカミがダギを食べるか、ダギがキャベツを食べるかの条件を方皋匏の制玄ずしお蚭定したす。
蟲民がいるず䟵略は䞍可胜

# Wolf cant stand with goat, and goat with cabbage without human. Not 2, not 0 which means that they are one the same side
Safe = [ And( Or(Wolf[i] != Goat[i], Wolf[i] == Human[i]), Or(Goat[i] != Cabbage[i], Goat[i] == Human[i])) for i in range(Num) ]

そしお最埌に、蟲倫が向こう岞に枡るずき、たたは戻っおくるずきに考えられるすべおの行動を定矩したす。
オオカミ、ダギ、キャベツを連れお行くこずも、誰も連れお行かないか、あるいはどこにも航海しないこずもできたす。

もちろん、蟲民なしでは誰も枡れたせん。

これは、川、ボヌト、および゚ンティティの埌続の各状態が、厳密に限定された方法でのみ前の状態ず異なる可胜性があるずいう事実によっお衚珟されたす。

ファヌマヌは䞀床に 2 ぀の゚ンティティのみを転送でき、すべおを䞀緒にしおおくこずはできないため、XNUMX ビット以䞋であり、その他倚くの制限がありたす。

Travel = [ Or(
And(Human[i] == Human[i+1] + 1, Wolf[i] == Wolf[i+1] + 1, Goat[i] == Goat[i+1], Cabbage[i] == Cabbage[i+1]),
And(Human[i] == Human[i+1] + 1, Goat[i] == Goat[i+1] + 1, Wolf[i] == Wolf[i+1], Cabbage[i] == Cabbage[i+1]),
And(Human[i] == Human[i+1] + 1, Cabbage[i] == Cabbage[i+1] + 1, Wolf[i] == Wolf[i+1], Goat[i] == Goat[i+1]),
And(Human[i] == Human[i+1] - 1, Wolf[i] == Wolf[i+1] - 1, Goat[i] == Goat[i+1], Cabbage[i] == Cabbage[i+1]),
And(Human[i] == Human[i+1] - 1, Goat[i] == Goat[i+1] - 1, Wolf[i] == Wolf[i+1], Cabbage[i] == Cabbage[i+1]),
And(Human[i] == Human[i+1] - 1, Cabbage[i] == Cabbage[i+1] - 1, Wolf[i] == Wolf[i+1], Goat[i] == Goat[i+1]),
And(Wolf[i] == Wolf[i+1], Goat[i] == Goat[i+1], Cabbage[i] == Cabbage[i+1])) for i in range(Num-1) ]

゜リュヌションを実行しおみたしょう。

solve(Side + Start + Finish + Safe + Travel)

そしお答えが分かりたした

Z3 は、すべおの条件を満たす䞀貫した状態のセットを芋぀けたした。
時空の四次元キャストの䞀皮。

䜕が起こったのか調べおみたしょう。

最終的には党員が枡ったこずがわかりたすが、最初だけ私たちの蟲倫は䌑むこずに決め、最初の2ステップではどこにも泳ぎたせんでした。

Human_2 = 0
Human_3 = 0

これは、遞択した州の数が過剰であり、8 ぀で十分であるこずを瀺唆しおいたす。

私たちの堎合、蟲倫はこれを行いたした。出発、䌑憩、䌑憩、ダギを暪切り、戻っおキャベツを暪切り、ダギず䞀緒に戻り、オオカミを暪切り、䞀人で戻り、ダギを再配達したす。

しかし最終的には問題は解決されたした。

#Старт.
 Human_1 = 0
 Wolf_1 = 0
 Goat_1 = 0
 Cabbage_1 = 0
 
 #ЀерЌер ПтЎыхает.
 Human_2 = 0
 Wolf_2 = 0
 Goat_2 = 0
 Cabbage_2 = 0
 
 #ЀерЌер ПтЎыхает.
 Human_3 = 0
 Wolf_3 = 0
 Goat_3 = 0
 Cabbage_3 = 0
 
 #ЀерЌер ПтвПзОт кПзу Ма МужМый берег.
 Human_4 = 1
 Wolf_4 = 0
 Goat_4 = 1
 Cabbage_4 = 0
 
 #ЀерЌер вПзвращается.
 Human_5 = 0
 Wolf_5 = 0
 Goat_5 = 1
 Cabbage_5 = 0
 
 #ЀерЌер ПтвПзОт капусту Ма МужМый берег.
 Human_6 = 1
 Wolf_6 = 0
 Cabbage_6 = 1
 Goat_6 = 1
 
 #Ключевая часть ПперацОО: ферЌер вПзвращает кПзу ПбратМП.
 Human_7 = 0
 Wolf_7 = 0
 Goat_7 = 0
 Cabbage_7 = 1
 
 #ЀерЌер ПтвПзОт вПлка Ма ЎругПй берег, гЎе ПМ теперь МахПЎОтся вЌесте с капустПй.
 Human_8 = 1
 Wolf_8 = 1
 Goat_8 = 0
 Cabbage_8 = 1
 
 #ЀерЌер вПзвращается за кПзПй.
 Human_9 = 0
 Wolf_9 = 1
 Goat_9 = 0
 Cabbage_9 = 1
 
 #ЀерЌер пПвтПрМП ЎПставляет кПзу Ма МужМый берег О завершают переправу.
 Human_10 = 1
 Wolf_10 = 1
 Goat_10 = 1
 Cabbage_10 = 1

次に、条件を倉曎しお、解決策がないこずを蚌明しおみたしょう。

これを行うには、オオカミに草食動物を䞎えたす。するず、オオカミはキャベツを食べたがるようになりたす。
これは、アプリケヌションを保護するこずが目暙であり、抜け穎がないこずを確認する必芁がある堎合ず比范できたす。

 Safe = [ And( Or(Wolf[i] != Goat[i], Wolf[i] == Human[i]), Or(Goat[i] != Cabbage[i], Goat[i] == Human[i]), Or(Wolf[i] != Cabbage[i], Goat[i] == Human[i])) for i in range(Num) ]

Z3 からは次のような回答が埗られたした。

 no solution

それは本圓に解決策がないこずを意味したす。

このようにしお、蟲倫に損倱を䞎えずに雑食性のオオカミず亀配するこずは䞍可胜であるこずをプログラム的に蚌明したした。

読者がこのトピックに興味があるず感じたら、今埌の蚘事で、通垞のプログラムたたは関数を圢匏的手法ず互換性のある方皋匏に倉換し、それを解く方法を説明したす。これにより、すべおの正圓なシナリオず脆匱性の䞡方が明らかになりたす。 最初は同じタスクですが、プログラムの圢匏で提瀺され、次にそれを埐々に耇雑にしお、゜フトりェア開発の䞖界の最新の䟋に移りたす。

次の蚘事はすでに準備されおいたす。
正匏な怜蚌システムを最初から䜜成する: PHP ず Python でシンボリック VM を䜜成する

その䞭で、問題の正匏な怜蚌からプログラムに移り、次のように説明したす。
それらを正匏なルヌルシステムに自動的に倉換するにはどうすればよいでしょうか。

出所 habr.com

コメントを远加したす