@@ -7,6 +7,8 @@ import lib/language/ic/term
77
88type StepMode { Deterministic(); NonDeterministic(); }
99
10+ record Substitution(from: SuperPort, to: SuperPort)
11+
1012effect fresh(): Int
1113
1214def freshener[R] { prog: => R / fresh }: R = {
@@ -18,10 +20,14 @@ def freshener[R] { prog: => R / fresh }: R = {
1820 }
1921}
2022
21- interface Rewrite {
23+ interface Interact {
2224 def annihilate(ctor: Constructor): Unit
2325 def construct(ctor: Constructor): Unit
24- def substitute(from: SuperPort, to: SuperPort): Unit
26+ def substitute(substitution: Substitution): Unit
27+
28+ def potential(port: PortRef): Unit
29+ def target(from: String): SuperPort
30+ def wire(from: Neg, to: Pos): Unit
2531}
2632
2733def redexes(program: Program): Unit / emit[Redex] =
@@ -31,44 +37,32 @@ def redexes(program: Program): Unit / emit[Redex] =
3137 if (ctorA.canInteract && ctorB.canInteract && ctorA.pp.name == ctorB.pp.name)
3238 do emit(Redex(ctorA, ctorB))
3339
34- def apply(port: SuperPort, substitutions: Ref[Map[SuperPort, SuperPort]]): SuperPort =
35- if (substitutions.get.contains(port)) {
36- val newPort = substitutions.get.getOrElse(port) { panic("wtf") }
37- substitutions.map { m => m.delete(port) }
38- newPort
39- } else port
40-
41- // Net...[x^p/y^p]...[z^p/x^p]... --> Net...[z^p/y^p]...
42- // Net...[z^p/x^p]...[x^p/y^p]... --> Net...[z^p/y^p]...
43- def apply(substitutees: Ref[Map[SuperPort, SuperPort]]) = {
44- def go(): Unit = {
45- var changed = false
46- substitutees.get.toList.foreach { (t){label} =>
47- val (to, from) = t
48- if (substitutees.get.contains(from)) {
49- changed = true
50- val newFrom = substitutees.get.getOrElse(from) { panic("wtf") }
51- substitutees.map { m => m.put(to, newFrom) }
52- substitutees.map { m => m.delete(from) }
53- label.break()
54- }
55- }
56- if (changed) go()
57- }
58- go()
59- }
40+ // TODO: this is horribly inefficient for now, but could be very efficient
41+ def redexes(program: Program, potential: List[PortRef]): Unit / emit[Redex] =
42+ with val ref = potential.foreach
43+ val port = ref.get
44+ with val ctorA = for { program() }
45+ with val ctorB = for { program() }
46+ if (ctorA.term::pp is Left(Neg(_)) and ctorB.term::pp is Right(Pos(_)))
47+ if (ctorA.canInteract && ctorB.canInteract && ctorA.pp.name == port && ctorB.pp.name == port)
48+ do emit(Redex(ctorA, ctorB))
6049
61- /// applies one-shot substitutions on constructor
62- def apply(ctor: Constructor, substitutions: Ref[Map[SuperPort, SuperPort]]): Constructor =
63- ctor.map { p => p.apply(substitutions).name }
50+ def freshWires(n: Int): (List[Neg], List[Pos]) / { Interact, fresh } = n.list::build { i =>
51+ val x = do fresh().show
52+ val from = Neg(x.ref)
53+ val to = Pos(x.ref)
54+ do wire(from, to)
55+ (from, to)
56+ }.unzip
6457
65- def interact(redex: Redex): Unit / { Rewrite , fresh } = redex match {
66- // @(f-, a-, k+) <> λ(x+, b-, f+) ~> [x+/a+ ][b-/k-]
58+ def interact(redex: Redex): Unit / { Interact , fresh } = redex match {
59+ // @(f-, a-, k+) <> λ(x+, b-, f+) ~> [a-/x- ][b-/k-]
6760 // beta-reduction: APP-LAM
6861 case Redex(Applicator(Neg(f1), Neg(a), Pos(k)), Abstractor(Pos(x), Neg(b), Pos(f2))) and f1 == f2 => {
69- // do substitute(Pos(x).super, Pos(a).super)
70- do substitute(Neg(a).super, Neg(x).super)
71- do substitute(Neg(b).super, Neg(k).super)
62+ do substitute(Substitution(Neg(a).super, do target(Pos(x).show)))
63+ do substitute(Substitution(Neg(b).super, do target(Pos(k).show)))
64+ do potential(a) // TODO: theoretically, we'd only need to somehow check if Neg(a) is at a principal port
65+ do potential(b)
7266 }
7367
7468 // δ(k-, k1+, ..., kn+) <> λ(x+, b-, k+) ~> σ(x+, x1-, ..., xn-), δ(b-, b1+, ..., bn+),
@@ -77,13 +71,16 @@ def interact(redex: Redex): Unit / { Rewrite, fresh } = redex match {
7771 case Redex(Duplicator(Neg(k1), ks, l), Abstractor(Pos(x), Neg(b), Pos(k2))) and k1 == k2 => {
7872 with on[OutOfBounds].panic() // can not happen
7973 val n = ks.size
80- val xs = n.list::build { i => do fresh().show }
81- val bs = n.list::build { i => do fresh().show }
82- do construct(Superposer(Pos(x), xs.map { xi => Neg(xi) } , l))
83- do construct(Duplicator(Neg(b), bs.map { bi => Pos(bi) } , l))
74+ val (xsNeg, xsPos) = n.freshWires()
75+ val (bsNeg, bsPos) = n.freshWires()
76+ do construct(Superposer(Pos(x), xsNeg , l))
77+ do construct(Duplicator(Neg(b), bsPos , l))
8478 0.each(n) { i =>
85- do construct(Abstractor(Pos(xs .get(i)), Neg(bs .get(i) ), ks.get(i)))
79+ do construct(Abstractor(xsPos .get(i), bsNeg .get(i), ks.get(i)))
8680 }
81+ do potential(x)
82+ do potential(b)
83+ ks.foreach { k => do potential(k.port) }
8784 }
8885
8986 // @(f-, a-, k+) <> σ(f+, f1-, ..., fn-) ~> σ(k+, k1-, ..., kn-), δ(a-, a1+, ..., an+),
@@ -92,20 +89,24 @@ def interact(redex: Redex): Unit / { Rewrite, fresh } = redex match {
9289 case Redex(Applicator(Neg(f1), Neg(a), Pos(k)), Superposer(Pos(f2), fs, l)) and f1 == f2 => {
9390 with on[OutOfBounds].panic() // can not happen
9491 val n = fs.size
95- val ks = n.list::build { i => do fresh().show }
96- val as = n.list::build { i => do fresh().show }
97- do construct(Superposer(Pos(k), ks.map { ki => Neg(ki) } , l))
98- do construct(Duplicator(Neg(a), as.map { ai => Pos(ai) } , l))
92+ val (ksNeg, ksPos) = n.freshWires()
93+ val (asNeg, asPos) = n.freshWires()
94+ do construct(Superposer(Pos(k), ksNeg , l))
95+ do construct(Duplicator(Neg(a), asPos , l))
9996 0.each(n) { i =>
100- do construct(Applicator(fs.get(i), Neg(as .get(i)), Pos(ks .get(i) )))
97+ do construct(Applicator(fs.get(i), asNeg .get(i), ksPos .get(i)))
10198 }
99+ fs.foreach { f => do potential(f.port) }
100+ do potential(a)
101+ do potential(k)
102102 }
103103
104104 // δ(k-) <> σ(k+, i1-, ..., im-) ~> δ(i1-), ..., δ(in-)
105105 // asymmetric eraser annihilation: DUP-SUP
106106 case Redex(Duplicator(Neg(k1), Nil(), l1), Superposer(Pos(k2), ins, l2)) and k1 == k2 => {
107107 ins.foreach { i =>
108108 do construct(Duplicator(i, Nil(), l1))
109+ do potential(i.port)
109110 }
110111 }
111112
@@ -114,15 +115,17 @@ def interact(redex: Redex): Unit / { Rewrite, fresh } = redex match {
114115 case Redex(Duplicator(Neg(k1), out, l1), Superposer(Pos(k2), Nil(), l2)) and k1 == k2 => {
115116 out.foreach { o =>
116117 do construct(Superposer(o, Nil(), l2))
118+ do potential(o.port)
117119 }
118120 }
119121
120122 // δ(k-, o1+, ..., on+) <> σ(k+, i1-, ..., im-) ~> [i1-/o1-]...[in-/on-]
121123 // symmetric duplicator annihilation: DUP-SUP
122124 case Redex(Duplicator(Neg(k1), out, l1), Superposer(Pos(k2), ins, l2)) and k1 == k2 and l1 == l2 and out.size == ins.size => {
123125 list::zip(out, ins).foreach { case (o, i) =>
124- do substitute(i.super, o.negate.super)
125- // do substitute(o.super, i.negate.super)
126+ // TODO: pre-substitute
127+ do substitute(Substitution(i.super, do target(o.show)))
128+ do potential(i.port)
126129 }
127130 }
128131
@@ -133,15 +136,20 @@ def interact(redex: Redex): Unit / { Rewrite, fresh } = redex match {
133136 with on[OutOfBounds].panic() // can not happen
134137 val n = out.size
135138 val m = ins.size
136- val fresh = max(n, m).list::build { _ => do fresh().show }
137- 0.each(m) { i => // duplicators
138- val outM = n.list::build { j => Pos(s"${fresh.get(i)}_${j.show}") }
139- do construct(Duplicator(ins.get(i), outM, l1))
140- }
141- 0.each(n) { i => // superposers
142- val insN = m.list::build { j => Neg(s"${fresh.get(j)}_${i.show}") }
143- do construct(Superposer(out.get(i), insN, l2))
139+ val d = max(n, m)
140+
141+ 0.each(d) { i =>
142+ val (insN, outM) = d.freshWires() // TODO: this constructs additional wires in unbalanced dups
143+ if (i < m) {
144+ do construct(Duplicator(ins.get(i), outM.take(m), l1))
145+ }
146+ if (i < n) {
147+ do construct(Superposer(out.get(i), insN.take(n), l2))
148+ }
144149 }
150+
151+ ins.foreach { i => do potential(i.port) }
152+ out.foreach { o => do potential(o.port) }
145153 }
146154
147155 case _ => {
@@ -150,43 +158,92 @@ def interact(redex: Redex): Unit / { Rewrite, fresh } = redex match {
150158 }
151159}
152160
153- def step_(program: Program, redex: Redex): Unit / { emit[Constructor], fresh } = {
161+ /// build up a static, doubly linked relationship between positive and negative ports
162+ /// the relationship is from SuperPort.show to SuperPort
163+ def wiring(program: Program): Map[String, SuperPort] = {
164+ var wiring: Map[String, SuperPort] = emptyGeneric() // pname -> target port
165+ var map: Map[String, SuperPort] = emptyGeneric() // name -> own port
166+
167+ def link(port: SuperPort): Unit = {
168+ map.get(port.name) match {
169+ case Some(target) =>
170+ wiring = wiring.put(port.show, target).put(target.show, port)
171+ case None() =>
172+ map = map.put(port.name, port)
173+ }
174+ }
175+
176+ try program()
177+ with emit[Constructor] { ctor =>
178+ ctor.ports.foreach { port => link(port) }
179+ resume(())
180+ }
181+ wiring
182+ }
183+
184+ def substitute(substitution: Substitution, wiring: Ref[Map[String, SuperPort]]) = {
185+ val Substitution(from, to) = substitution
186+ println(s"[${from.show}/${to.show}]")
187+ // val x = to.port.get
188+ to.port.set(from.port.get)
189+ // from.port.set(x)
190+ wiring.map { w => w.put(to.show, from).put(from.show, to) }
191+ }
192+
193+ def step_(program: Program, redex: Redex): List[PortRef] / { emit[Constructor], fresh } = {
154194 val annihilated = ref[Set[Constructor]](emptyGeneric())
155- val constructed = ref[Set[Constructor]](emptyGeneric())
156- val substitutions = ref[Map[SuperPort, SuperPort]](emptyGeneric())
195+ val constructed = ref[List[Constructor]](Nil())
196+ val potential = ref[List[PortRef]](Nil())
197+ val wiring = ref(program.wiring())
198+
199+ println(program.show)
157200
158201 try {
159202 redex.interact()
160203 do annihilate(redex.left)
161204 do annihilate(redex.right)
162- } with Rewrite {
205+ } with Interact {
163206 def annihilate(ctor) = resume(annihilated.map { s => s.insert(ctor) })
164207 def construct(ctor) = resume(do emit(ctor))
165- def substitute(from, to) = resume(substitutions.map { m => m.put(to, from) })
208+ def substitute(substitution) = resume(substitution.substitute(wiring))
209+ def potential(port) = resume(potential.map { l => Cons(port, l) })
210+ def target(from) = resume(wiring.get.getOrElse(from) { panic(s"invalid target: ${from.show}") })
211+ def wire(from, to) = resume(wiring.map { w => w.put(from.show, to.super).put(to.show, from.super) })
166212 }
167213
168- // print("\nsubst before: ")
169- // substitutions.get.foreach { (to, from) => print("${from.show}/${to.show}, ") }
170- substitutions.apply()
171- // print("\n subst after: ")
172- // substitutions.get.foreach { (to, from) => print("${from.show}/${to.show}, ") }
173- // println("\n")
174-
214+ println("\nemitting:")
175215 for { program() } { ctor =>
176- if (not(annihilated.get.contains(ctor)))
177- do emit(ctor.apply(substitutions))
216+ if (not(annihilated.get.contains(ctor))) {
217+ println(ctor.show)
218+ do emit(ctor)
219+ }
178220 }
221+
222+ potential.get
223+ }
224+
225+ def pop[A] { stream: => Unit / emit[A] }: A / { fail, emit[A] } = {
226+ try {
227+ def body(): Option[A] = { stream(); None() }
228+ body()
229+ } with emit[A] { a =>
230+ val next = resume(())
231+ if (next is Some(a)) do emit(a)
232+ Some(a)
233+ }.getOrFail
179234}
180235
181- def choose (mode: StepMode, redexes: RedexBag): Redex / fail = mode match {
182- case Deterministic() => first [Redex] { redexes() }
183- case NonDeterministic() => choose { redexes() }
236+ def pop (mode: StepMode, redexes: RedexBag): Redex / { fail, emit[Redex] } = mode match {
237+ case Deterministic() => pop [Redex] { redexes() }
238+ case NonDeterministic() => choose { redexes() } // TODO
184239}
185240
186- // TODO: emit new redexes directly during interactions (wires get reconnected, check if same port)
187241def step(program: Program, mode: StepMode, redexes: RedexBag): Unit / { emit[Constructor], emit[Redex], fresh, fail } = {
188- val redex = choose(mode, redexes)
189- val program: Program = collect { program.step_(redex) }
242+ //val redex = pop(mode, redexes) // TODO!
243+ val redex = pop(NonDeterministic(), redexes)
244+ println(s"\n=== REDEX: ${redex.show} ===")
245+ val tup: (List[PortRef], Program) = returning::collect { program.step_(redex) }
246+ val (potential, program) = tup
190247
191248 // println(list::collect[Constructor] { program() }.show { ctor => ctor.show })
192249
@@ -195,10 +252,12 @@ def step(program: Program, mode: StepMode, redexes: RedexBag): Unit / { emit[Con
195252 val negPorts = collect[Constructor] { program() }.flatMap { ctor => ctor.ports }.filter { p => p.isNeg }.map { p => p.name }.set::fromListGeneric
196253 if (posPorts.difference(negPorts).size != 0) {
197254 println("\n!!! FATAL " ++ posPorts.toList.show ++ " vs " ++ negPorts.toList.show)
198- println("\nREDEX: " ++ redex.left.show ++ " - " ++ redex.right.show)
255+ // println("\nREDEX: " ++ redex.left.show ++ " - " ++ redex.right.show)
199256 println(posPorts.difference(negPorts).toList.show)
200257 } else {
201- program.redexes() // TODO: this could be an expensive call, we should not do it at every step.
258+ // println(potential)
259+ //program.redexes(potential)
260+ program.redexes()
202261 program()
203262 }
204263}
@@ -212,7 +271,7 @@ def normalize(program: Program, redexes: RedexBag, max: Int): (Program, Int) = {
212271 with exhaustively((empty(), 0))
213272 count = count + 1
214273 state = returning::collect {
215- collect { state.first.step(NonDeterministic (), state.second) } }
274+ collect { state.first.step(Deterministic (), state.second) } }
216275 if (count > max) do fail()
217276 (state.first, count)
218277}
0 commit comments