package granary
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Pure-OCaml SQL engine
Install
dune-project
Dependency
Authors
Maintainers
Sources
0.0.3.tar.gz
sha256=8b18780ea373be48301d9f333925860a2f9110fc0ac28684295118d72b65a67e
sha512=25ca3c9c5e2b528704a542502e0f37dc33ba003f65622d969b8c2b800778585f8ef0cf89b36e6679832e3993e8303aecddfc662742baf7044d6afe4a796b8f11
doc/src/granary.ivm/aggregate.ml.html
Source file aggregate.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88module type SPEC = sig module In : Zset.S module Out : Zset.S type group val compare_group : group -> group -> int val group_of : In.elt -> group val measure : In.elt -> int val result : group -> int -> Out.elt end module Make (S : SPEC) = struct module GMap = Map.Make (struct type t = S.group let compare = S.compare_group end) (* Per-group running totals: [mult] is Σ weight (the group exists iff [mult > 0]); [aggv] is Σ measure*weight (the value of its result row). *) type acc = { mult : int ; aggv : int } type t = { mutable groups : acc GMap.t ; mutable out : S.Out.t } let create () = { groups = GMap.empty; out = S.Out.zero } let zero_acc = { mult = 0; aggv = 0 } let get m g = match GMap.find_opt g m with | Some a -> a | None -> zero_acc ;; (* The per-group [(mult, aggv)] change contributed by one input delta. *) let group_deltas delta = S.In.fold (fun e w acc -> let g = S.group_of e in let cur = get acc g in GMap.add g { mult = cur.mult + w; aggv = cur.aggv + (S.measure e * w) } acc) delta GMap.empty ;; (* The output delta for one group transitioning [old_acc] -> [new_acc]: retract the old visible row (if it existed) and insert the new one (if it exists). *) let row_delta g old_acc new_acc = let d = S.Out.zero in let d = if old_acc.mult > 0 then S.Out.add d (S.Out.singleton (S.result g old_acc.aggv) (-1)) else d in if new_acc.mult > 0 then S.Out.add d (S.Out.singleton (S.result g new_acc.aggv) 1) else d ;; let step t delta = let out_delta = ref S.Out.zero in GMap.iter (fun g d -> let old_acc = get t.groups g in let new_acc = { mult = old_acc.mult + d.mult; aggv = old_acc.aggv + d.aggv } in out_delta := S.Out.add !out_delta (row_delta g old_acc new_acc); (* Prune ONLY when both totals are zero. A SUM group whose weights cancel to [mult = 0] but [aggv <> 0] is deliberately kept: dropping it would lose [aggv] and corrupt the value if the group later revives. (For COUNT this never arises — [aggv = mult].) On a high-churn SUM view such net-zero groups accumulate; bound it in Phase 3 if needed. *) t.groups <- (if new_acc.mult = 0 && new_acc.aggv = 0 then GMap.remove g t.groups else GMap.add g new_acc t.groups)) (group_deltas delta); t.out <- S.Out.add t.out !out_delta; !out_delta ;; let output t = t.out end
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>