Created
October 9, 2013 16:12
-
-
Save y-taka-23/6903806 to your computer and use it in GitHub Desktop.
Alloy による十進位取り記数法のモデリング
This file contains 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