12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788moduletypeSPEC=sigmoduleIn:Zset.SmoduleOut:Zset.Stypegroupvalcompare_group:group->group->intvalgroup_of:In.elt->groupvalmeasure:In.elt->intvalresult:group->int->Out.eltendmoduleMake(S:SPEC)=structmoduleGMap=Map.Make(structtypet=S.groupletcompare=S.compare_groupend)(* Per-group running totals: [mult] is Σ weight (the group exists iff [mult >
0]); [aggv] is Σ measure*weight (the value of its result row). *)typeacc={mult:int;aggv:int}typet={mutablegroups:accGMap.t;mutableout:S.Out.t}letcreate()={groups=GMap.empty;out=S.Out.zero}letzero_acc={mult=0;aggv=0}letgetmg=matchGMap.find_optgmwith|Somea->a|None->zero_acc;;(* The per-group [(mult, aggv)] change contributed by one input delta. *)letgroup_deltasdelta=S.In.fold(funewacc->letg=S.group_ofeinletcur=getaccginGMap.addg{mult=cur.mult+w;aggv=cur.aggv+(S.measuree*w)}acc)deltaGMap.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). *)letrow_deltagold_accnew_acc=letd=S.Out.zeroinletd=ifold_acc.mult>0thenS.Out.addd(S.Out.singleton(S.resultgold_acc.aggv)(-1))elsedinifnew_acc.mult>0thenS.Out.addd(S.Out.singleton(S.resultgnew_acc.aggv)1)elsed;;letsteptdelta=letout_delta=refS.Out.zeroinGMap.iter(fungd->letold_acc=gett.groupsginletnew_acc={mult=old_acc.mult+d.mult;aggv=old_acc.aggv+d.aggv}inout_delta:=S.Out.add!out_delta(row_deltagold_accnew_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<-(ifnew_acc.mult=0&&new_acc.aggv=0thenGMap.removegt.groupselseGMap.addgnew_acct.groups))(group_deltasdelta);t.out<-S.Out.addt.out!out_delta;!out_delta;;letoutputt=t.outend