diff --git a/src/diff.mo b/src/diff.mo new file mode 100644 index 0000000..6cf7009 --- /dev/null +++ b/src/diff.mo @@ -0,0 +1,49 @@ +import Array "mo:stdlib/array"; +import Hash "mo:stdlib/hash"; +import HashMap "mo:stdlib/hashMap"; +import PQ "pq"; + +module { + public type Time = Nat; + public type Diff = Int; + public type ValueDiff = { + time: Time; + diff: Diff; + }; + public type Trace = HashMap.HashMap>; + public type ExportTrace = [(Key, [ValueDiff])]; + + func ord(x: ValueDiff, y: ValueDiff): Bool { x.time < y.time }; + + public class Collection( + keyEq: (K,K) -> Bool, + keyHash: K -> Hash.Hash) { + public let trace: Trace = HashMap.HashMap(0, keyEq, keyHash); + public func exportTrace(): ExportTrace { + var res: ExportTrace = []; + for ((k, diffs) in trace.iter()) { + let vec_diffs = diffs.heap.toArray(); + res := Array.append<(K, [ValueDiff])>(res, [(k, vec_diffs)]); + }; + return res; + }; + public func insert(k: K, t: Time) { + let diff = { time = t; diff = 1 }; + let diffs = switch (trace.get(k)) { + case null { let pq = PQ.PQ(ord); pq.add(diff); pq }; + case (?diffs) { diffs.add(diff); diffs }; + }; + ignore trace.set(k, diffs); + }; + public func map(f:K -> K): Collection { + let res = Collection(keyEq, keyHash); + for ((k,diffs) in trace.iter()) { + let new_k = f(k); + for (diff in diffs.heap.iter()) { + res.insert(new_k, diff.time); + } + }; + return res; + } + }; +} diff --git a/src/main.mo b/src/main.mo index 014bf49..693a6ca 100644 --- a/src/main.mo +++ b/src/main.mo @@ -1,9 +1,11 @@ import A "mo:stdlib/array"; -import P "mo:stdlib/prelude"; -import List "mo:stdlib/list"; +import B "mo:stdlib/buf"; +import Diff "diff"; import H "mo:stdlib/hashMap"; import Hash "mo:stdlib/hash"; -import B "mo:stdlib/buf"; +import List "mo:stdlib/list"; +import P "mo:stdlib/prelude"; +import D "mo:stdlib/debug"; let N = 600; @@ -137,4 +139,13 @@ actor { public query func output() : async ([Object], Int, Int, Int) { (E.objects.toArray(), E.pos.x, E.pos.y, E.pos.dir) }; + + public func testDiff(): async Diff.ExportTrace { + let a = Diff.Collection(varEq, Hash.hashOfText); + a.insert("a",0); a.insert("b",0); + a.insert("a",1); a.insert("c",1); + D.print(debug_show(a.exportTrace())); + let b = a.map(func (x:Text): Text = x#"_" ); + return b.exportTrace(); + }; }; diff --git a/src/pq.mo b/src/pq.mo new file mode 100644 index 0000000..d20a37a --- /dev/null +++ b/src/pq.mo @@ -0,0 +1,65 @@ +import Buf "mo:stdlib/buf"; +import D "mo:stdlib/debug"; + +module { + public class PQ(ord: (T, T) -> Bool) { + public let heap = Buf.Buf(0); + public func add(x: T) { + let i = heap.len(); + heap.add(x); + up_heap(i); + }; + /* + public func pop(): ?T { + let n = heap.len(); + if (n == 0) { + return null; + }; + let x = h.get(0); + let y = h.get(n - 1); + h.set(0, y); + // h.remove_last(); + down_heap(pq, 0); + ?x + }; + func down_heap(pq: PQ, i: Nat) { + let h = pq.heap; + let ord = pq.order; + let n = h.len(); + let x = h.get(i); + func down_heap(j: Nat) { + if (2 * j + 1 < n) { + let l = 2 * j + 1; + let r = 2 * j + 2; + let k = if (r < n and not ord(h.get(l), h.get(r))) { r } else { l }; + let y = h.get(k); + if (ord(x, y)) { + h.set(j, x); + } else { + h.set(j, y); + down_heap(k); + } + } else if (j != i) { + h.set(j, x); + } + }; + down_heap(i) + };*/ + func up_heap(i: Nat) { + let x = heap.get(i); + func up_heap_(j: Nat) { + let k = (j - 1) / 2; + let y = heap.get(k); + if (j == 0 or ord(y,x)) { + heap.set(j, x); + } else { + heap.set(j, y); + up_heap_(k); + } + }; + if (i > 0) { + up_heap_(i); + }; + }; + }; +}