util.bend checks
raw source on the hub · import 0x527a2a4fa91b05a0250d7be0e11d232a/util.bend as Util
Shared helpers. Parallelize independent list splits; keep these total.
Population maps use mid-split + a b = f(lo) f(hi) (bend guide Parallelism).
Fuel is |xs| so the Nat shrinks; halves stay observationally ordered.
1 import
import Base
Definitions
def list_len source · line 7 · raw
@-A:Data -> @xs:List<&2, A> -> Nat
def list_take_pad source · line 12 · raw
@-A:Data -> @+fill:A -> @xs:List<&2, A> -> @+n:Nat -> List<&2, A>
|take(xs ++ replicate(n, fill), n)| = n. Identity when |xs| = n (take never reads the pad). Used to lock Run / select to the law size.
def word_all_false source · line 17 · raw
@n:Nat -> @w:Word(n) -> Bool
IEEE +0.0 is the all-false Word(32). Definitional on the 0.0 literal, so p=0 operator laws skip F32.is_gt / F32.is_eq (opaque Base laws).
def f32_is_zero source · line 28 · raw
@x:F32 -> Bool
def nat_min.fin source · line 33 · raw
@+a:Nat -> @+b:Nat -> @c:Bool -> Nat
def nat_min source · line 40 · raw
@+a:Nat -> @+b:Nat -> Nat
def nat_max.fin source · line 43 · raw
@+a:Nat -> @+b:Nat -> @c:Bool -> Nat
def nat_max source · line 50 · raw
@+a:Nat -> @+b:Nat -> Nat
def nat_pow source · line 53 · raw
@+b:Nat -> @e:Nat -> Nat
def binomial source · line 61 · raw
@+n:Nat -> @+k:Nat -> Nat
C(n, k). Das–Dennis count = C(p + M - 1, M - 1).
def in_nats source · line 70 · raw
@+x:Nat -> @xs:List<&2, Nat> -> Bool
def keep_if source · line 73 · raw
@-A:Data -> @+h:A -> @rest:List<&2, A> -> @keep:Bool -> List<&2, A>
def minus.put source · line 80 · raw
@h:Nat -> @rest:List<&2, Nat> -> @drop:Bool -> List<&2, Nat>
def minus source · line 87 · raw
@+xs:List<&2, Nat> -> @+ys:List<&2, Nat> -> List<&2, Nat>
def get_nat source · line 94 · raw
@xs:List<&2, Nat> -> @i:Nat -> Nat
def inc_at source · line 97 · raw
@+xs:List<&2, Nat> -> @+i:Nat -> List<&2, Nat>
def zeros_nat source · line 100 · raw
@n:Nat -> List<&2, Nat>
def nats_sum source · line 104 · raw
@xs:List<&2, Nat> -> Nat
Sum of a Nat histogram. Used to lock mid-split count conservation.
def bit source · line 113 · raw
@b:Bool -> Nat
1 when i is a valid bin of a length-n histogram, else 0. List.set (and therefore inc_at) is a no-op at i >= n.
def bin_hit source · line 120 · raw
@+i:Nat -> @+n:Nat -> Nat
def nats_add source · line 123 · raw
@a:List<&2, Nat> -> @b:List<&2, Nat> -> List<&2, Nat>
def vec_min source · line 134 · raw
@a:List<&2, F32> -> @b:List<&2, F32> -> List<&2, F32>
def vec_max source · line 145 · raw
@a:List<&2, F32> -> @b:List<&2, F32> -> List<&2, F32>
def vec_sub source · line 156 · raw
@a:List<&2, F32> -> @b:List<&2, F32> -> List<&2, F32>
def vec_scale source · line 167 · raw
@+s:F32 -> @v:List<&2, F32> -> List<&2, F32>
def vec_dot source · line 174 · raw
@a:List<&2, F32> -> @b:List<&2, F32> -> F32
def vec_sqnorm source · line 185 · raw
@+v:List<&2, F32> -> F32
def ones_f32 source · line 188 · raw
@n:Nat -> List<&2, F32>
def zeros_f32 source · line 191 · raw
@n:Nat -> List<&2, F32>
def get_f32 source · line 194 · raw
@xs:List<&2, F32> -> @i:Nat -> F32
def set_f32 source · line 197 · raw
@xs:List<&2, F32> -> @i:Nat -> @x:F32 -> List<&2, F32>
def f32_or_one source · line 200 · raw
@+span:F32 -> @tiny:Bool -> F32
def denom source · line 208 · raw
@+lo:F32 -> @+hi:F32 -> F32
C# Normalize: denom < 1e-12 → 1.0 (intercept span uses the same floor).
def vec_norm_div source · line 212 · raw
@f:List<&2, F32> -> @ideal:List<&2, F32> -> @nadir:List<&2, F32> -> List<&2, F32>
def csv_step source · line 223 · raw
@x:F32 -> @acc:String -> String
def show_f32s source · line 230 · raw
@xs:List<&2, F32> -> String
def f32s_eq source · line 233 · raw
@a:List<&2, F32> -> @b:List<&2, F32> -> Bool
def has_f32s source · line 244 · raw
@+needle:List<&2, F32> -> @xs:List<&2, List<&2, F32>> -> Bool
def g12_scale source · line 258 · raw
F32
Decision-variable duplicate key: 12 decimal places, round(x*1e12)/1e12. C# DecisionKey is double.ToString("G12") (12 significant digits). Those are not the same format. Near magnitude 1, F32 ULP is coarser than 1e-12, so 12-dp rounding often does nothing. Below about 1e-5 a 12-dp bin is wider than the F32 ULP and the round changes the value (1.234567e-8 → 1.2346e-8). This tree keeps 12-dp keys. It does not match C# G12. See src/g12_key.bend.
def g12_round_abs source · line 261 · raw
@+x:F32 -> F32
def g12_one.signed source · line 265 · raw
@+x:F32 -> @neg:Bool -> F32
def g12_one source · line 272 · raw
@+x:F32 -> F32
def g12_vec.go source · line 336 · raw
@xs:List<&2, F32> -> @acc:List<&2, F32> -> List<&2, F32>
Sequential cons walk (guide: the list is the shape a flat loop walks). n_var is 12–30 on the oracles; mid-split take/drop of that spine is more expensive than a tail walk. Same rounding as the old map_halves.
def g12_vec source · line 343 · raw
@xs:List<&2, F32> -> List<&2, F32>
Templates
template map_halves.go source · line 278 · raw
@-A:Data -> @-B:Data -> @-C:Data -> @-f:(@+c:C -> @+x:A -> B) -> @+ctx:C -> @+fuel:Nat -> @xs:List<&2, A> -> List<&2, B>
Balanced fork-join map. Singleton / empty stay sequential. Fuel 0 is a
total fallback (public callers pass |xs|). ~f is a closed top-level.
Mid take/drop is inlined: a computed pair cannot be matched.
template map_halves source · line 302 · raw
@-A:Data -> @-B:Data -> @-C:Data -> @-f:(@+c:C -> @+x:A -> B) -> @+ctx:C -> @+xs:List<&2, A> -> List<&2, B>
template filter_halves.go source · line 307 · raw
@-A:Data -> @-C:Data -> @-p:(@+c:C -> @+x:A -> Bool) -> @+ctx:C -> @+fuel:Nat -> @xs:List<&2, A> -> List<&2, A>
Independent keep/drop. Mid-split; take ++ drop matches the old
tail-first cons_if walk (original relative order).
template filter_halves source · line 330 · raw
@-A:Data -> @-C:Data -> @-p:(@+c:C -> @+x:A -> Bool) -> @+ctx:C -> @+xs:List<&2, A> -> List<&2, A>