11import test
22import tty
33import set
4+ import map
45
56import lib/utils
67import lib/net/net
@@ -14,34 +15,58 @@ def confluence(n: Int) { test: => Unit / Assertion }: Unit / Assertion = {
1415 0.each(n) { i =>
1516 try test()
1617 with Assertion {
17- def assert(condition, msg) = do assert(condition, s"${msg} (run number ${i.show})")
18+ def assert(condition, msg) = resume( do assert(condition, s"${msg} (run number ${i.show})") )
1819 }
1920 }
2021 test()
2122}
2223
23- // for now mostly heuristics
24+ /// equivalence after renaming
2425def assertEquivalent(bs: List[Constructor], as: List[Constructor]): Unit / { Formatted, Assertion } = {
25- // TODO: ordering?
26- // TODO: map for actual alpha equivalence
26+ // TODO: do not require same ordering
27+
28+ with on[MissingValue].default { assertTrue(false, s"constructor mismatch:\n${bs.show}\n vs\n${as.show}") }
29+
30+ var counter = 0
31+ var aMap: Map[String, String] = emptyGeneric()
32+ var bMap: Map[String, String] = emptyGeneric()
33+ as.zip(bs).foreach { case (a, b) =>
34+ assertTrue(a.sameKind(b), s"expected same constructor kind in\n${b.show}\n vs\n${a.show}")
35+ a.ports.zip(b.ports).foreach { case (pa, pb) =>
36+ if (aMap.contains(pa.name) || bMap.contains(pb.name)) {
37+ // these accesses should potentially fail
38+ val aName = aMap.get(pa.name).value
39+ val bName = bMap.get(pb.name).value
40+ assertEqual(aName, bName, s"expected same name, but got ${aName} and ${bName} in\n${b.show}\n vs\n${a.show}")
41+ assertEqual(pa.isPos, pb.isPos, s"expected same polarity in\n${b.show}\n vs \n${a.show}")
42+ } else {
43+ aMap = aMap.put(pa.name, counter.show)
44+ bMap = bMap.put(pb.name, counter.show)
45+ }
46+ }
47+ }
48+ assertEqual(as.size, bs.size)
2749
50+ // TODO: this check should be redundant now
2851 val aPorts = fromListGeneric(as.flatMap { ctor => ctor.ports.map { p => p.name } })
2952 val bPorts = fromListGeneric(bs.flatMap { ctor => ctor.ports.map { p => p.name } })
30- assertEqual(aPorts.size, bPorts.size, s"Expected ${aPorts.size.show} unique variables, but got ${bPorts.size.show}:\n" ++ aPorts.toList.show ++ " vs " ++ bPorts.toList.show ++ "\nin " ++ as.show ++ "\nvs " ++ bs.show)
31-
32- as.zip(bs).foreach {
33- case (Abstractor(Pos(x1), Neg(b1), Pos(k1)), Abstractor(Pos(x2), Neg(b2), Pos(k2))) => ()
34- case (Applicator(Neg(f1), Neg(a1), Pos(k1)), Applicator(Neg(f2), Neg(a2), Pos(k2))) => ()
35- case (Duplicator(Neg(o1), ins1, label1), Duplicator(Neg(o2), ins2, label2)) =>
36- assertEqual(ins1.size, ins2.size)
37- assertEqual(label1, label2)
38- case (Superposer(Pos(i1), out1, label1), Superposer(Pos(i2), out2, label2)) =>
39- assertEqual(out1.size, out2.size)
40- assertEqual(label1, label2)
41- case (Initiator(Neg(k1)), Initiator(Neg(k2))) => ()
42- case (_, _) => assertEqual(as, bs) { (a, b) => a == b } { c => c.show } // will fail, but we'll see why
53+ assertEqual(aPorts.size, bPorts.size, s"Expected ${aPorts.size.show} unique variables, but got ${bPorts.size.show}:\n${aPorts.toList.show} vs ${bPorts.toList.show}\nin ${as.show}\nvs ${bs.show}")
54+ }
55+
56+ record Confluence(value: Int)
57+ record Steps(value: Int)
58+
59+ def normalizeWith(term: String, conf: Confluence, steps: Steps, normalized: List[Constructor]) = {
60+ with confluence(conf.value)
61+ val program: Program = collect {
62+ with assertNoThrow[WrongFormat]
63+ with source[Char] { term.each }
64+ compile!()
4365 }
44- assertEqual(as.size, bs.size)
66+ val redexes = box { program.redexes() }
67+ val (_normalized, _steps) = normalize(program, redexes, steps.value + 10)
68+ assertEqual(_steps, steps.value)
69+ assertEquivalent(list::collect[Constructor] { _normalized() }, normalized)
4570}
4671
4772def tests() = suite("└ ruler tests") {
@@ -67,80 +92,36 @@ def tests() = suite("└ ruler tests") {
6792 }
6893
6994 test("normalization: identity duplication") {
70- with confluence(5)
71- val program: Program = collect {
72- with assertNoThrow[WrongFormat]
73- with source[Char] { "(x=>(x x) x=>x)".each }
74- compile!()
75- }
76- val redexes = box { program.redexes() }
77- val (normalized, steps) = normalize(program, redexes, 10)
78- assertEqual(steps, 4)
79- assertEquivalent(list::collect[Constructor] { normalized() }, [
95+ "(x=>(x x) x=>x)".normalizeWith(Confluence(5), Steps(4), [
8096 Abstractor(Pos("xSym6_1_1".ref), Neg("xSym6_1_1".ref), Pos("xSym6_0_0".ref)),
8197 Initiator(Neg("xSym6_0_0".ref))
8298 ])
8399 }
84100
85101 test("normalization: more complex identity annihilation") {
86- with confluence(50)
87- val program: Program = collect {
88- with assertNoThrow[WrongFormat]
89- with source[Char] { "(x=>x x=>(x x) x=>x)".each }
90- compile!()
91- }
92- val redexes = box { program.redexes() }
93- val (normalized, steps) = normalize(program, redexes, 10)
94- assertEqual(steps, 5)
95- assertEquivalent(list::collect[Constructor] { normalized() }, [
102+ "(x=>x x=>(x x) x=>x)".normalizeWith(Confluence(50), Steps(5), [
96103 Abstractor(Pos("xSym9_1_1".ref), Neg("xSym9_1_1".ref), Pos("xSym9_0_0".ref)),
97104 Initiator(Neg("xSym9_0_0".ref))
98105 ])
99106 }
100107
101- test("normalization: multi-arity identity annihilation") {
102- with confluence(50)
103- val program: Program = collect {
104- with assertNoThrow[WrongFormat]
105- with source[Char] { "(x=>(x x x x x x x x x) x=>x)".each }
106- compile!()
107- }
108- val redexes = box { program.redexes() }
109- val (normalized, steps) = normalize(program, redexes, 20)
110- assertEqual(steps, 11)
111- assertEquivalent(list::collect[Constructor] { normalized() }, [
112- Abstractor(Pos("xSym20_8_8".ref), Neg("xSym20_8_8".ref), Pos("xSym20_7_7".ref)),
113- Initiator(Neg("xSym20_7_7".ref))
108+ test("normalization: multi-dup identity annihilation") {
109+ "(x=>(x x x x x x x x x) x=>x)".normalizeWith(Confluence(50), Steps(11), [
110+ Abstractor(Pos("xSym9_1_1".ref), Neg("xSym9_1_1".ref), Pos("xSym9_0_0".ref)),
111+ Initiator(Neg("xSym9_0_0".ref))
114112 ])
115113 }
116114
117115 test("normalization: church identity annihilation") {
118- with confluence(50)
119- val program: Program = collect {
120- with assertNoThrow[WrongFormat]
121- with source[Char] { "(s=>z=>(s (s (s (s (s (s z)))))) x=>x)".each }
122- compile!()
123- }
124- val redexes = box { program.redexes() }
125- val (normalized, steps) = normalize(program, redexes, 20)
126- assertEqual(steps, 9)
127- assertEquivalent(list::collect[Constructor] { normalized() }, [
116+ "(s=>z=>(s (s (s (s (s (s z)))))) x=>x)".normalizeWith(Confluence(50), Steps(9), [
128117 Abstractor(Pos("xSym9_1_1".ref), Neg("xSym9_1_1".ref), Pos("kAbs6".ref)),
129118 Initiator(Neg("kAbs6".ref))
130119 ])
131120 }
132121
122+ // this broke once! but only because of different ordering, so TODO: better equivalence check
133123 test("normalization: church i* annihilation") {
134- with confluence(50)
135- val program: Program = collect {
136- with assertNoThrow[WrongFormat]
137- with source[Char] { "(s=>z=>(s (s (s (s (s (s z)))))) x=>y=>(x y))".each }
138- compile!()
139- }
140- val redexes = box { program.redexes() }
141- val (normalized, steps) = normalize(program, redexes, 20)
142- assertEqual(steps, 17)
143- assertEquivalent(list::collect[Constructor] { normalized() }, [ // x => y => (x y)
124+ "(s=>z=>(s (s (s (s (s (s z)))))) x=>y=>(x y))".normalizeWith(Confluence(50), Steps(17), [
144125 Applicator(Neg("xSym17_5_5".ref), Neg("ySym18_17_5".ref), Pos("kApp19_19_1".ref)), // (x y)
145126 Abstractor(Pos("ySym18_17_5".ref), Neg("kApp19_19_1".ref), Pos("kAbs20_6_0".ref)), // y =>
146127 Abstractor(Pos("xSym17_5_5".ref), Neg("kAbs20_6_0".ref), Pos("kAbs14".ref)), // x =>
@@ -149,16 +130,7 @@ def tests() = suite("└ ruler tests") {
149130 }
150131
151132 test("normalization: church bruijnification") {
152- with confluence(50)
153- val program: Program = collect {
154- with assertNoThrow[WrongFormat]
155- with source[Char] { "(s=>z=>(s (s z)) x=>y=>x)".each }
156- compile!()
157- }
158- val redexes = box { program.redexes() }
159- val (normalized, steps) = normalize(program, redexes, 20)
160- assertEqual(steps, 7)
161- assertEquivalent(list::collect[Constructor] { normalized() }, [ // x9_4 => y11_4 => y11_5 => x9_4
133+ "(s=>z=>(s (s z)) x=>y=>x)".normalizeWith(Confluence(50), Steps(7), [
162134 Duplicator(Neg("yEra11_4_0".ref), Nil(), 1),
163135 Duplicator(Neg("yEra11_5_1".ref), Nil(), 1),
164136 Abstractor(Pos("yEra11_4_0".ref), Neg("xSym9_0_0".ref), Pos("kAbs10_2_0".ref)), // y11_4 =>
@@ -169,32 +141,14 @@ def tests() = suite("└ ruler tests") {
169141 }
170142
171143 test("normalization: erasing church") {
172- with confluence(50)
173- val program: Program = collect {
174- with assertNoThrow[WrongFormat]
175- with source[Char] { "(x=>y=>y s=>z=>(s (s (s z))))".each }
176- compile!()
177- }
178- val redexes = box { program.redexes() }
179- val (normalized, steps) = normalize(program, redexes, 20)
180- assertEqual(steps, 11)
181- assertEquivalent(list::collect[Constructor] { normalized() }, [
144+ "(x=>y=>y s=>z=>(s (s (s z))))".normalizeWith(Confluence(50), Steps(11), [
182145 Abstractor(Pos("ySym1".ref), Neg("ySym1".ref), Pos("kAbs2".ref)),
183146 Initiator(Neg("kAbs2".ref))
184147 ])
185148 }
186149
187150 test("normalization: s k k") {
188- with confluence(50)
189- val program: Program = collect {
190- with assertNoThrow[WrongFormat]
191- with source[Char] { "(x=>y=>z=>(x z (y z)) x=>y=>x x=>y=>x)".each }
192- compile!()
193- }
194- val redexes = box { program.redexes() }
195- val (normalized, steps) = normalize(program, redexes, 10)
196- assertEqual(steps, 7)
197- assertEquivalent(list::collect[Constructor] { normalized() }, [
151+ "(x=>y=>z=>(x z (y z)) x=>y=>x x=>y=>x)".normalizeWith(Confluence(50), Steps(7), [
198152 Duplicator(Neg("zSym5".ref), Nil(), 1),
199153 Duplicator(Neg("zDup9".ref), [Pos("zSym2".ref), Pos("zSym5".ref)], 0),
200154 Abstractor(Pos("zDup9".ref), Neg("zSym2".ref), Pos("kAbs8".ref)),
@@ -205,16 +159,7 @@ def tests() = suite("└ ruler tests") {
205159 val iota = "s=>(s x=>y=>z=>(x z (y z)) x=>y=>x)"
206160
207161 test("normalization: iota iota") {
208- with confluence(50)
209- val program: Program = collect {
210- with assertNoThrow[WrongFormat]
211- with source[Char] { s"(${iota} ${iota})".each }
212- compile!()
213- }
214- val redexes = box { program.redexes() }
215- val (normalized, steps) = normalize(program, redexes, 20)
216- assertEqual(steps, 19)
217- assertEquivalent(list::collect[Constructor] { normalized() }, [
162+ s"(${iota} ${iota})".normalizeWith(Confluence(50), Steps(19), [
218163 Duplicator(Neg("zDup29".ref), [Pos("zSym22".ref), Pos("zSym25".ref)], 2),
219164 Abstractor(Pos("zDup29".ref), Neg("zSym22".ref), Pos("kAbs28".ref)),
220165 Duplicator(Neg("zSym25".ref), [], 2),
@@ -223,16 +168,7 @@ def tests() = suite("└ ruler tests") {
223168 }
224169
225170 test("normalization: iota iota iota iota") {
226- with confluence(50)
227- val program: Program = collect {
228- with assertNoThrow[WrongFormat]
229- with source[Char] { s"(${iota} (${iota} (${iota} ${iota})))".each }
230- compile!()
231- }
232- val redexes = box { program.redexes() }
233- val (normalized, steps) = normalize(program, redexes, 70)
234- assertEqual(steps, 67)
235- assertEquivalent(list::collect[Constructor] { normalized() }, [
171+ s"(${iota} (${iota} (${iota} ${iota})))".normalizeWith(Confluence(50), Steps(67), [
236172 Duplicator(Neg("38".ref), Nil(), 1),
237173 Abstractor(Pos("38".ref), Neg("34".ref), Pos("36".ref)), // y => x
238174 Abstractor(Pos("34".ref), Neg("36".ref), Pos("32_0".ref)), // x =>
0 commit comments