Created
October 9, 2013 16:12
-
-
Save y-taka-23/6903806 to your computer and use it in GitHub Desktop.
Alloy による十進位取り記数法のモデリング
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ************************************ | |
| // 十進法による符号なし整数演算のモデル | |
| // ************************************ | |
| open util/ordering[Position] | |
| // ------------------------------------ | |
| // 位取り記数法のモデリング | |
| // ------------------------------------ | |
| // 位取りの位置 | |
| sig Position { | |
| inverse : one Position // 桁の順番を逆転させたときの位置 | |
| } | |
| // 桁の逆転に関する制約 | |
| fact inversePosition { | |
| // 逆転は対称 | |
| inverse in ~ inverse | |
| // 最初の桁と最後の桁は逆転させることで移り変わる | |
| Position <: first -> Position <: last in inverse | |
| // その他の桁に関する帰納的な定義 | |
| all p1 : Position - last, p2 : Position - first | | |
| p1 -> p2 in inverse => p1.next -> p2.prev in inverse | |
| } | |
| // 各桁の数字 | |
| enum Digit { D0, D1, D2, D3, D4, D5, D6, D7, D8, D9 } | |
| // 十進位取り記数法による符号なし整数 | |
| sig Decimal { | |
| // すべての桁に数字が配置されていることに注意 | |
| // リトルエンディアン (Position が first 側が一の位) とする | |
| notation : Position -> one Digit | |
| } | |
| // 十進表記が一致すれば整数として一致 | |
| fact uniqueNotation { | |
| all n1, n2 : Decimal | n1.notation = n2.notation => n1 = n2 | |
| } | |
| // ------------------------------------ | |
| // 加算の実装 | |
| // ------------------------------------ | |
| // 十進半加算器 | |
| // a, b は入力、s は (元の桁に残る) 和、c は上位桁への繰り上がり | |
| pred halfAdd (a, b, s, c : Digit) { | |
| (a = D0 && b = D0) => (s = D0 && c = D0) | |
| (a = D0 && b = D1) => (s = D1 && c = D0) | |
| (a = D0 && b = D2) => (s = D2 && c = D0) | |
| (a = D0 && b = D3) => (s = D3 && c = D0) | |
| (a = D0 && b = D4) => (s = D4 && c = D0) | |
| (a = D0 && b = D5) => (s = D5 && c = D0) | |
| (a = D0 && b = D6) => (s = D6 && c = D0) | |
| (a = D0 && b = D7) => (s = D7 && c = D0) | |
| (a = D0 && b = D8) => (s = D8 && c = D0) | |
| (a = D0 && b = D9) => (s = D9 && c = D0) | |
| (a = D1 && b = D0) => (s = D1 && c = D0) | |
| (a = D1 && b = D1) => (s = D2 && c = D0) | |
| (a = D1 && b = D2) => (s = D3 && c = D0) | |
| (a = D1 && b = D3) => (s = D4 && c = D0) | |
| (a = D1 && b = D4) => (s = D5 && c = D0) | |
| (a = D1 && b = D5) => (s = D6 && c = D0) | |
| (a = D1 && b = D6) => (s = D7 && c = D0) | |
| (a = D1 && b = D7) => (s = D8 && c = D0) | |
| (a = D1 && b = D8) => (s = D9 && c = D0) | |
| (a = D1 && b = D9) => (s = D0 && c = D1) | |
| (a = D2 && b = D0) => (s = D2 && c = D0) | |
| (a = D2 && b = D1) => (s = D3 && c = D0) | |
| (a = D2 && b = D2) => (s = D4 && c = D0) | |
| (a = D2 && b = D3) => (s = D5 && c = D0) | |
| (a = D2 && b = D4) => (s = D6 && c = D0) | |
| (a = D2 && b = D5) => (s = D7 && c = D0) | |
| (a = D2 && b = D6) => (s = D8 && c = D0) | |
| (a = D2 && b = D7) => (s = D9 && c = D0) | |
| (a = D2 && b = D8) => (s = D0 && c = D1) | |
| (a = D2 && b = D9) => (s = D1 && c = D1) | |
| (a = D3 && b = D0) => (s = D3 && c = D0) | |
| (a = D3 && b = D1) => (s = D4 && c = D0) | |
| (a = D3 && b = D2) => (s = D5 && c = D0) | |
| (a = D3 && b = D3) => (s = D6 && c = D0) | |
| (a = D3 && b = D4) => (s = D7 && c = D0) | |
| (a = D3 && b = D5) => (s = D8 && c = D0) | |
| (a = D3 && b = D6) => (s = D9 && c = D0) | |
| (a = D3 && b = D7) => (s = D0 && c = D1) | |
| (a = D3 && b = D8) => (s = D1 && c = D1) | |
| (a = D3 && b = D9) => (s = D2 && c = D1) | |
| (a = D4 && b = D0) => (s = D4 && c = D0) | |
| (a = D4 && b = D1) => (s = D5 && c = D0) | |
| (a = D4 && b = D2) => (s = D6 && c = D0) | |
| (a = D4 && b = D3) => (s = D7 && c = D0) | |
| (a = D4 && b = D4) => (s = D8 && c = D0) | |
| (a = D4 && b = D5) => (s = D9 && c = D0) | |
| (a = D4 && b = D6) => (s = D0 && c = D1) | |
| (a = D4 && b = D7) => (s = D1 && c = D1) | |
| (a = D4 && b = D8) => (s = D2 && c = D1) | |
| (a = D4 && b = D9) => (s = D3 && c = D1) | |
| (a = D5 && b = D0) => (s = D5 && c = D0) | |
| (a = D5 && b = D1) => (s = D6 && c = D0) | |
| (a = D5 && b = D2) => (s = D7 && c = D0) | |
| (a = D5 && b = D3) => (s = D8 && c = D0) | |
| (a = D5 && b = D4) => (s = D9 && c = D0) | |
| (a = D5 && b = D5) => (s = D0 && c = D1) | |
| (a = D5 && b = D6) => (s = D1 && c = D1) | |
| (a = D5 && b = D7) => (s = D2 && c = D1) | |
| (a = D5 && b = D8) => (s = D3 && c = D1) | |
| (a = D5 && b = D9) => (s = D4 && c = D1) | |
| (a = D6 && b = D0) => (s = D6 && c = D0) | |
| (a = D6 && b = D1) => (s = D7 && c = D0) | |
| (a = D6 && b = D2) => (s = D8 && c = D0) | |
| (a = D6 && b = D3) => (s = D9 && c = D0) | |
| (a = D6 && b = D4) => (s = D0 && c = D1) | |
| (a = D6 && b = D5) => (s = D1 && c = D1) | |
| (a = D6 && b = D6) => (s = D2 && c = D1) | |
| (a = D6 && b = D7) => (s = D3 && c = D1) | |
| (a = D6 && b = D8) => (s = D4 && c = D1) | |
| (a = D6 && b = D9) => (s = D5 && c = D1) | |
| (a = D7 && b = D0) => (s = D7 && c = D0) | |
| (a = D7 && b = D1) => (s = D8 && c = D0) | |
| (a = D7 && b = D2) => (s = D9 && c = D0) | |
| (a = D7 && b = D3) => (s = D0 && c = D1) | |
| (a = D7 && b = D4) => (s = D1 && c = D1) | |
| (a = D7 && b = D5) => (s = D2 && c = D1) | |
| (a = D7 && b = D6) => (s = D3 && c = D1) | |
| (a = D7 && b = D7) => (s = D4 && c = D1) | |
| (a = D7 && b = D8) => (s = D5 && c = D1) | |
| (a = D7 && b = D9) => (s = D6 && c = D1) | |
| (a = D8 && b = D0) => (s = D8 && c = D0) | |
| (a = D8 && b = D1) => (s = D9 && c = D0) | |
| (a = D8 && b = D2) => (s = D0 && c = D1) | |
| (a = D8 && b = D3) => (s = D1 && c = D1) | |
| (a = D8 && b = D4) => (s = D2 && c = D1) | |
| (a = D8 && b = D5) => (s = D3 && c = D1) | |
| (a = D8 && b = D6) => (s = D4 && c = D1) | |
| (a = D8 && b = D7) => (s = D5 && c = D1) | |
| (a = D8 && b = D8) => (s = D6 && c = D1) | |
| (a = D8 && b = D9) => (s = D7 && c = D1) | |
| (a = D9 && b = D0) => (s = D9 && c = D0) | |
| (a = D9 && b = D1) => (s = D0 && c = D1) | |
| (a = D9 && b = D2) => (s = D1 && c = D1) | |
| (a = D9 && b = D3) => (s = D2 && c = D1) | |
| (a = D9 && b = D4) => (s = D3 && c = D1) | |
| (a = D9 && b = D5) => (s = D4 && c = D1) | |
| (a = D9 && b = D6) => (s = D5 && c = D1) | |
| (a = D9 && b = D7) => (s = D6 && c = D1) | |
| (a = D9 && b = D8) => (s = D7 && c = D1) | |
| (a = D9 && b = D9) => (s = D8 && c = D1) | |
| } | |
| // 十進全可算器 | |
| pred fullAdd (a, b, cIn, s, cOut : Digit) { | |
| some s1, cOut1, cOut2 : Digit { | |
| halfAdd[a, b, s1, cOut1] | |
| halfAdd[s1, cIn, s, cOut2] | |
| // 最後の半加算器では桁上がりは発生しない (c = D0) ことに注意 | |
| halfAdd[cOut1, cOut2, cOut, D0] | |
| } | |
| } | |
| // 十進数同士の加算の関係 : n1 + n2 = answer | |
| pred decPlus (n1, n2, answer : Decimal) { | |
| // cOuts により各桁の繰り上がりをメモ化する | |
| some cOuts : Decimal | | |
| let n1n = n1.notation, n2n = n2.notation, | |
| ansn = answer.notation, cosn = cOuts.notation { | |
| halfAdd[n1n[first], n2n[first], ansn[first], cosn[first]] | |
| all p : Position - first | | |
| fullAdd[n1n[p], n2n[p], cosn[p.prev], ansn[p], cosn[p]] | |
| } | |
| } | |
| // 例 : 794 + 1192 = 1986 | |
| pred example794Plus1192 { | |
| some n1, n2, answer : Decimal | | |
| let n1n = n1.notation, n2n = n2.notation { | |
| // n1 = 794 | |
| n1n[first] = D4 | |
| n1n[first.next] = D9 | |
| n1n[first.next.next] = D7 | |
| all p : Position | | |
| p in nexts[first.next.next] => n1n[p] = D0 | |
| // n2 = 1192 | |
| n2n[first] = D2 | |
| n2n[first.next] = D9 | |
| n2n[first.next.next] = D1 | |
| n2n[first.next.next.next] = D1 | |
| all p : Position | | |
| p in nexts[first.next.next.next] => n2n[p] = D0 | |
| // n1 + n2 = answer | |
| decPlus[n1, n2, answer] | |
| } | |
| } | |
| run example794Plus1192 for 4 Position, 4 Decimal, 0 DecArray | |
| // ------------------------------------ | |
| // 乗算の実装 | |
| // ------------------------------------ | |
| // 十進乗算器ユニット | |
| // a, b は入力、結果は十進表示整数で返す | |
| pred digitProd (a, b : Digit, answer : Decimal) { | |
| let ansn = answer.notation { | |
| (a = D0 && b = D0) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D0 && b = D1) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D0 && b = D2) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D0 && b = D3) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D0 && b = D4) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D0 && b = D5) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D0 && b = D6) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D0 && b = D7) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D0 && b = D8) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D0 && b = D9) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D1 && b = D0) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D1 && b = D1) => (ansn[first] = D1 && ansn[first.next] = D0) | |
| (a = D1 && b = D2) => (ansn[first] = D2 && ansn[first.next] = D0) | |
| (a = D1 && b = D3) => (ansn[first] = D3 && ansn[first.next] = D0) | |
| (a = D1 && b = D4) => (ansn[first] = D4 && ansn[first.next] = D0) | |
| (a = D1 && b = D5) => (ansn[first] = D5 && ansn[first.next] = D0) | |
| (a = D1 && b = D6) => (ansn[first] = D6 && ansn[first.next] = D0) | |
| (a = D1 && b = D7) => (ansn[first] = D7 && ansn[first.next] = D0) | |
| (a = D1 && b = D8) => (ansn[first] = D8 && ansn[first.next] = D0) | |
| (a = D1 && b = D9) => (ansn[first] = D9 && ansn[first.next] = D0) | |
| (a = D2 && b = D0) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D2 && b = D1) => (ansn[first] = D2 && ansn[first.next] = D0) | |
| (a = D2 && b = D2) => (ansn[first] = D4 && ansn[first.next] = D0) | |
| (a = D2 && b = D3) => (ansn[first] = D6 && ansn[first.next] = D0) | |
| (a = D2 && b = D4) => (ansn[first] = D8 && ansn[first.next] = D0) | |
| (a = D2 && b = D5) => (ansn[first] = D0 && ansn[first.next] = D1) | |
| (a = D2 && b = D6) => (ansn[first] = D2 && ansn[first.next] = D1) | |
| (a = D2 && b = D7) => (ansn[first] = D4 && ansn[first.next] = D1) | |
| (a = D2 && b = D8) => (ansn[first] = D6 && ansn[first.next] = D1) | |
| (a = D2 && b = D9) => (ansn[first] = D8 && ansn[first.next] = D1) | |
| (a = D3 && b = D0) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D3 && b = D1) => (ansn[first] = D3 && ansn[first.next] = D0) | |
| (a = D3 && b = D2) => (ansn[first] = D6 && ansn[first.next] = D0) | |
| (a = D3 && b = D3) => (ansn[first] = D9 && ansn[first.next] = D0) | |
| (a = D3 && b = D4) => (ansn[first] = D2 && ansn[first.next] = D1) | |
| (a = D3 && b = D5) => (ansn[first] = D5 && ansn[first.next] = D1) | |
| (a = D3 && b = D6) => (ansn[first] = D8 && ansn[first.next] = D1) | |
| (a = D3 && b = D7) => (ansn[first] = D1 && ansn[first.next] = D2) | |
| (a = D3 && b = D8) => (ansn[first] = D4 && ansn[first.next] = D2) | |
| (a = D3 && b = D9) => (ansn[first] = D7 && ansn[first.next] = D2) | |
| (a = D4 && b = D0) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D4 && b = D1) => (ansn[first] = D4 && ansn[first.next] = D0) | |
| (a = D4 && b = D2) => (ansn[first] = D8 && ansn[first.next] = D0) | |
| (a = D4 && b = D3) => (ansn[first] = D2 && ansn[first.next] = D1) | |
| (a = D4 && b = D4) => (ansn[first] = D6 && ansn[first.next] = D1) | |
| (a = D4 && b = D5) => (ansn[first] = D0 && ansn[first.next] = D2) | |
| (a = D4 && b = D6) => (ansn[first] = D4 && ansn[first.next] = D2) | |
| (a = D4 && b = D7) => (ansn[first] = D8 && ansn[first.next] = D2) | |
| (a = D4 && b = D8) => (ansn[first] = D2 && ansn[first.next] = D3) | |
| (a = D4 && b = D9) => (ansn[first] = D6 && ansn[first.next] = D3) | |
| (a = D5 && b = D0) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D5 && b = D1) => (ansn[first] = D5 && ansn[first.next] = D0) | |
| (a = D5 && b = D2) => (ansn[first] = D0 && ansn[first.next] = D1) | |
| (a = D5 && b = D3) => (ansn[first] = D5 && ansn[first.next] = D1) | |
| (a = D5 && b = D4) => (ansn[first] = D0 && ansn[first.next] = D2) | |
| (a = D5 && b = D5) => (ansn[first] = D5 && ansn[first.next] = D2) | |
| (a = D5 && b = D6) => (ansn[first] = D0 && ansn[first.next] = D3) | |
| (a = D5 && b = D7) => (ansn[first] = D5 && ansn[first.next] = D3) | |
| (a = D5 && b = D8) => (ansn[first] = D0 && ansn[first.next] = D4) | |
| (a = D5 && b = D9) => (ansn[first] = D5 && ansn[first.next] = D4) | |
| (a = D6 && b = D0) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D6 && b = D1) => (ansn[first] = D6 && ansn[first.next] = D0) | |
| (a = D6 && b = D2) => (ansn[first] = D2 && ansn[first.next] = D1) | |
| (a = D6 && b = D3) => (ansn[first] = D8 && ansn[first.next] = D1) | |
| (a = D6 && b = D4) => (ansn[first] = D4 && ansn[first.next] = D2) | |
| (a = D6 && b = D5) => (ansn[first] = D0 && ansn[first.next] = D3) | |
| (a = D6 && b = D6) => (ansn[first] = D6 && ansn[first.next] = D3) | |
| (a = D6 && b = D7) => (ansn[first] = D2 && ansn[first.next] = D4) | |
| (a = D6 && b = D8) => (ansn[first] = D8 && ansn[first.next] = D4) | |
| (a = D6 && b = D9) => (ansn[first] = D4 && ansn[first.next] = D5) | |
| (a = D7 && b = D0) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D7 && b = D1) => (ansn[first] = D7 && ansn[first.next] = D0) | |
| (a = D7 && b = D2) => (ansn[first] = D4 && ansn[first.next] = D1) | |
| (a = D7 && b = D3) => (ansn[first] = D1 && ansn[first.next] = D2) | |
| (a = D7 && b = D4) => (ansn[first] = D8 && ansn[first.next] = D2) | |
| (a = D7 && b = D5) => (ansn[first] = D5 && ansn[first.next] = D3) | |
| (a = D7 && b = D6) => (ansn[first] = D2 && ansn[first.next] = D4) | |
| (a = D7 && b = D7) => (ansn[first] = D9 && ansn[first.next] = D4) | |
| (a = D7 && b = D8) => (ansn[first] = D6 && ansn[first.next] = D5) | |
| (a = D7 && b = D9) => (ansn[first] = D3 && ansn[first.next] = D6) | |
| (a = D8 && b = D0) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D8 && b = D1) => (ansn[first] = D8 && ansn[first.next] = D0) | |
| (a = D8 && b = D2) => (ansn[first] = D6 && ansn[first.next] = D1) | |
| (a = D8 && b = D3) => (ansn[first] = D4 && ansn[first.next] = D2) | |
| (a = D8 && b = D4) => (ansn[first] = D2 && ansn[first.next] = D3) | |
| (a = D8 && b = D5) => (ansn[first] = D0 && ansn[first.next] = D4) | |
| (a = D8 && b = D6) => (ansn[first] = D8 && ansn[first.next] = D4) | |
| (a = D8 && b = D7) => (ansn[first] = D6 && ansn[first.next] = D5) | |
| (a = D8 && b = D8) => (ansn[first] = D4 && ansn[first.next] = D6) | |
| (a = D8 && b = D9) => (ansn[first] = D2 && ansn[first.next] = D7) | |
| (a = D9 && b = D0) => (ansn[first] = D0 && ansn[first.next] = D0) | |
| (a = D9 && b = D1) => (ansn[first] = D9 && ansn[first.next] = D0) | |
| (a = D9 && b = D2) => (ansn[first] = D8 && ansn[first.next] = D1) | |
| (a = D9 && b = D3) => (ansn[first] = D7 && ansn[first.next] = D2) | |
| (a = D9 && b = D4) => (ansn[first] = D6 && ansn[first.next] = D3) | |
| (a = D9 && b = D5) => (ansn[first] = D5 && ansn[first.next] = D4) | |
| (a = D9 && b = D6) => (ansn[first] = D4 && ansn[first.next] = D5) | |
| (a = D9 && b = D7) => (ansn[first] = D3 && ansn[first.next] = D6) | |
| (a = D9 && b = D8) => (ansn[first] = D2 && ansn[first.next] = D7) | |
| (a = D9 && b = D9) => (ansn[first] = D1 && ansn[first.next] = D8) | |
| all p : Position - (first + first.next) | ansn[p] = D0 | |
| } | |
| } | |
| // 上位桁側への論理シフト | |
| pred upperShift (n, shifted : Decimal) { | |
| let nn = n.notation, sftn = shifted.notation { | |
| sftn[first] = D0 | |
| all p : Position - first | sftn[p] = nn[p.prev] | |
| } | |
| } | |
| // シフトと加算の組合せ : n1 + n2 * 10 = answer | |
| pred shiftingPlus (n1, n2, answer : Decimal) { | |
| some shifted : Decimal { | |
| upperShift[n2, shifted] | |
| decPlus[n1, shifted, answer] | |
| } | |
| } | |
| // メモ化用の配列 | |
| sig DecArray { | |
| // 十進表示の桁数と同じ長さを持ち、null 値は不可 | |
| get : Position -> one Decimal | |
| } | |
| // 一桁ずつシフトしながら加算 | |
| pred foldShiftingPlus (ns : DecArray, answer : Decimal) { | |
| // acc により畳み込みの途中経過をメモ化 | |
| some acc : DecArray { | |
| // ns に対して逆順に畳み込みを行う | |
| acc.get[first] = ns.get[last] | |
| all p : Position - first | | |
| shiftingPlus[ns.get[p.inverse], acc.get[p.prev], acc.get[p]] | |
| acc.get[last] = answer | |
| } | |
| } | |
| // 十進数同士の乗算の関係 : n1 * n2 = answer | |
| pred decMul (n1, n2, answer : Decimal) { | |
| // pProds により部分積をメモ化 | |
| // pProds.get[i] は n1 全体と、n2 の i 桁目との部分積 | |
| some pProds : DecArray | let n1n = n1.notation, n2n = n2.notation { | |
| all i : Position | some dProds : DecArray { | |
| // n1 の j 桁目と n2 の i 桁目との積を計算して | |
| // j に関してシフトしつつ和を取ると部分積が得られる | |
| all j : Position | digitProd[n1n[j], n2n[i], dProds.get[j]] | |
| foldShiftingPlus[dProds, pProds.get[i]] | |
| } | |
| // さらに i に対してシフトしつつ和を取ると最終的な積が得られる | |
| foldShiftingPlus[pProds, answer] | |
| } | |
| } | |
| // 例 : 13 * 57 = 741 | |
| // Skolem depth >= 2 推奨 | |
| pred example13Times57 { | |
| some n1, n2, answer : Decimal | | |
| let n1n = n1.notation, n2n = n2.notation { | |
| // n1 = 13 | |
| n1n[first] = D3 | |
| n1n[first.next] = D1 | |
| all p : Position | p in nexts[first.next] => n1n[p] = D0 | |
| // n2 = 57 | |
| n2n[first] = D7 | |
| n2n[first.next] = D5 | |
| all p : Position | p in nexts[first.next] => n2n[p] = D0 | |
| // n1 * n2 = answer | |
| decMul[n1, n2, answer] | |
| } | |
| } | |
| run example13Times57 for 3 Position, 14 Decimal, 7 DecArray |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment