code wiki / (root) / nx_icecream_bench.nx

nx_icecream_bench.nx source

↩ module page · 538 lines · 22866 B

1// nx_icecream_bench.nx -- THE RULER. Score a frozen dessert against Ben & 2// Jerry's Vanilla, the declared SOTA reference for this lane. 3// 4// ===== WHY A RULER COMES FIRST ==================================== 5// 6// "Exceed Ben & Jerry's" is not a formulation instruction until something can 7// SCORE both products on the same axes. This organ is that scorer. It holds 8// no ambition and proposes no recipe: it computes what a label implies, what 9// the law actually permits, and where the reference product is structurally 10// weak. The formulator is a separate organ and must be argued WITH this one, 11// never instead of it. 12// 13// ===== THE REFERENCE, FROM THE ACTUAL LABEL ======================= 14// 15// Ben & Jerry's Vanilla, US pint, UPC 076840400058. Ingredient declaration 16// in order: Cream, Skim Milk, Liquid Sugar (Sugar, Water), Water, Egg Yolks, 17// Sugar, Guar Gum, Vanilla Extract, Vanilla Beans, Carrageenan. 18// 19// Nutrition panel, 2/3 cup (143 g) serving: 330 kcal, 21 g fat (14 g sat), 20// 29 g carbohydrate (28 g sugars), 6 g protein, 95 mg cholesterol. 21// Pint = 16 fl oz = 473 mL, 3 servings => 429 g net. The net weight is 22// DERIVED (US frozen dessert is sold by volume; weight is not declared), and 23// bench_net_weight_is_derived says so. 24// 25// **TWO FACTS IN THAT DECLARATION DECIDE THE WHOLE COMPETITIVE PICTURE:** 26// 1. The only hydrocolloids are GUAR (primary) and CARRAGEENAN (secondary). 27// There is no locust bean gum -- which matters because this lane's own 28// gap ledger had named LBG as "how industry slows recrystallisation". 29// The actual competitor does not use it. 30// 2. There is NO ADDED EMULSIFIER. Egg yolk is the entire emulsifier 31// system -- no mono- and diglycerides, no polysorbate 80. That is the 32// exploitable weakness, and it is the reason this organ models meltdown. 33// 34// ===== THE LEGAL FINDING THIS ORGAN CARRIES ======================= 35// 36// 21 CFR 135.110 imposes FOUR floors on anything labelled "ice cream": 37// >=10% milkfat, >=20% total milk solids, >=4.5 lb/gal finished weight, and 38// >=1.6 lb TOTAL FOOD SOLIDS per gallon. nx_icecream enforces the first 39// three. It declares IC_FDA_MIN_FOOD_SOLIDS_Q2 = 160 for the fourth and 40// then never reads it -- a dead constant, so the fourth floor is documented 41// and unenforced. 42// 43// **THE TWO WEIGHT-SIDE FLOORS BIND IN DIFFERENT REGIMES.** The air ceiling 44// is set by whichever floor is reached first, and which one that is depends 45// on total solids: 46// 47// rho_min_weight = 4.5 lb/gal (constant) 48// rho_min_solids = 1.6 lb/gal / TS_fraction (rises as solids fall) 49// 50// They cross at TS = 355 permil. ABOVE that the weight floor binds and the 51// shipped one-floor law is right by luck. BELOW it the SOLIDS floor binds 52// and the shipped law over-permits -- it licenses air that would put the 53// product outside the standard of identity. bench_shipped_law_error_permil 54// measures the gap rather than asserting it. 55// 56// ★The direction is the unsafe one: it permits MORE air than the law allows, 57// so the failure mode is a mislabelled product, not a conservative one. 58// 59// All INTEGER. _q2 = x100, _q3 = x1000, _permil = x1000 (fraction). 60// 61// Grounding (cited): 62// fda_21cfr135_110_ice_cream_standard_of_identity (four floors) 63// fda_21cfr101_12_racc_frozen_desserts (2/3 cup basis) 64// goff_guelph_overrun_and_mix_density (specific volumes) 65// liu_sala_scholten_2023_food_hydrocolloids_138 (meltdown vs destab) 66// herald_2008_egg_yolk_replacement_french_vanilla (yolk melts fastest) 67// benjerry_vanilla_label_upc_076840400058 (the reference) 68// 69// genealogy_id: frozen_dessert_science + nishi_food_science_suite 70 71import "nx_syscalls.nx" 72const BENCH_MAGIC_10000: i64 = 10000 73const BENCH_MAGIC_1000000: i64 = 1000000 74 75// ===== Verdicts ======================================================= 76 77const BENCH_INVALID: i64 = 0 - 1 78 79// Which of the two weight-side floors is binding. 80const BENCH_FLOOR_NONE: i64 = 0 81const BENCH_FLOOR_WEIGHT: i64 = 1 82const BENCH_FLOOR_SOLIDS: i64 = 2 83 84// Emulsifier systems, in ascending order of fat-destabilising power. 85const BENCH_EMUL_NONE: i64 = 0 86const BENCH_EMUL_EGG_YOLK: i64 = 1 87const BENCH_EMUL_MONO_DI: i64 = 2 88const BENCH_EMUL_MONO_DI_PS80: i64 = 3 89 90// ===== Physical + legal constants ===================================== 91 92// Partial specific volumes, mL/g x1000 (Guelph mix-density model). Fat is 93// less dense than water; serum solids are much denser. 94const BENCH_SV_FAT_Q3: i64 = 1075 95const BENCH_SV_SNF_Q3: i64 = 630 96const BENCH_SV_WATER_Q3: i64 = 1000 97 98const BENCH_ML_PER_GAL: i64 = 3785 99const BENCH_G_PER_LB: i64 = 454 100 101const BENCH_FDA_MIN_LB_PER_GAL_Q2: i64 = 450 // 4.5 lb/gal finished weight 102const BENCH_FDA_MIN_FOOD_SOLIDS_Q2: i64 = 160 // 1.6 lb food solids/gal 103const BENCH_FDA_MIN_MILKFAT_PERMIL: i64 = 100 104const BENCH_FDA_MIN_MILK_SOL_PERMIL: i64 = 200 105 106// 2/3 cup RACC for frozen desserts, in TENTHS of a mL: 157.725 mL. 107const BENCH_RACC_TENTH_ML: i64 = 1577 108 109// ===== A product under test ========================================== 110// 111// Everything here is readable off a US nutrition panel plus the pack volume. 112// serving_ml_tenth is the RACC in tenths of a mL. 113 114struct BenchProduct { 115 serving_g: i64, 116 serving_ml_tenth: i64, 117 fat_g: i64, 118 carb_g: i64, 119 protein_g: i64, 120 ash_permil: i64, // of the serving; ~8 permil for dairy 121 emulsifier: i64, 122 net_weight_derived: i64, 123} 124 125func bench_product_new() -> *BenchProduct { 126 let p: *BenchProduct = sys_mmap(96) as *BenchProduct 127 p.serving_g = 0 128 p.serving_ml_tenth = BENCH_RACC_TENTH_ML 129 p.fat_g = 0 130 p.carb_g = 0 131 p.protein_g = 0 132 p.ash_permil = 8 133 p.emulsifier = BENCH_EMUL_NONE 134 p.net_weight_derived = 0 135 return p 136} 137 138// Ben & Jerry's Vanilla -- the declared SOTA reference. Every field is off 139// the verified label; net weight is derived, and the flag records that. 140func bench_ref_benjerry() -> *BenchProduct { 141 let p: *BenchProduct = bench_product_new() 142 p.serving_g = 143 143 p.serving_ml_tenth = BENCH_RACC_TENTH_ML 144 p.fat_g = 21 145 p.carb_g = 29 146 p.protein_g = 6 147 p.emulsifier = BENCH_EMUL_EGG_YOLK 148 p.net_weight_derived = 1 149 return p 150} 151 152// Haagen-Dazs Vanilla -- the other super-premium anchor. Ingredients are 153// cream, skim milk, cane sugar, egg yolks, vanilla extract: NO stabiliser 154// and no added emulsifier at all. 155// 156// ⚠⚠ONLY THE SERVING WEIGHT IS VERIFIED FOR THIS PRODUCT. Its nutrition 157// panel was not retrieved, so there is no BenchProduct for it -- encoding a 158// guessed panel would let bench_overrun_of() return a confident number built 159// on invented macros, which is the exact failure this lane exists to refuse. 160// What IS verified is the serving weight at the same 2/3 cup RACC, and that 161// alone supports the only claim worth making here. 162const BENCH_HD_SERVING_G: i64 = 128 163 164func bench_hd_density_q3() -> i64 { 165 return BENCH_HD_SERVING_G * BENCH_MAGIC_10000 / BENCH_RACC_TENTH_ML 166} 167 168func bench_hd_composition_is_known() -> i64 { return 0 } 169 170// ★THE ASSUMPTION-FREE COMPARISON. Both panels declare the same 2/3 cup 171// RACC, so their serving weights are weights of equal volumes: the density 172// ratio needs no mix model, no overrun derivation, and no composition at 173// all. Returns permil by which the reference is denser than Haagen-Dazs. 174func bench_denser_than_hd_permil(p: *BenchProduct) -> i64 { 175 let a: i64 = bench_density_q3(p) 176 let b: i64 = bench_hd_density_q3() 177 if a == BENCH_INVALID { return BENCH_INVALID } 178 if b <= 0 { return BENCH_INVALID } 179 return a * 1000 / b - 1000 180} 181 182// ===== Composition off the panel ===================================== 183 184// Finished product density, g/mL x1000. This is the ONE measured quantity 185// the whole overrun derivation rests on, and it needs no model. 186func bench_density_q3(p: *BenchProduct) -> i64 { 187 if p.serving_ml_tenth <= 0 { return BENCH_INVALID } 188 if p.serving_g <= 0 { return BENCH_INVALID } 189 return p.serving_g * BENCH_MAGIC_10000 / p.serving_ml_tenth 190} 191 192func bench_fat_permil(p: *BenchProduct) -> i64 { 193 if p.serving_g <= 0 { return BENCH_INVALID } 194 return p.fat_g * 1000 / p.serving_g 195} 196 197// Total solids = fat + carbohydrate + protein + ash. Water is the rest. 198func bench_total_solids_permil(p: *BenchProduct) -> i64 { 199 if p.serving_g <= 0 { return BENCH_INVALID } 200 let macro: i64 = p.fat_g + p.carb_g + p.protein_g 201 return macro * 1000 / p.serving_g + p.ash_permil 202} 203 204func bench_water_permil(p: *BenchProduct) -> i64 { 205 let ts: i64 = bench_total_solids_permil(p) 206 if ts == BENCH_INVALID { return BENCH_INVALID } 207 return 1000 - ts 208} 209 210// Milk-solids-not-fat, inferred from protein. Milk protein is 36 permil of 211// MSNF, so MSNF = protein / 0.36. INFERRED, not declared. 212func bench_msnf_permil(p: *BenchProduct) -> i64 { 213 if p.serving_g <= 0 { return BENCH_INVALID } 214 let prot: i64 = p.protein_g * 1000 / p.serving_g 215 return prot * 1000 / 360 216} 217 218func bench_total_milk_solids_permil(p: *BenchProduct) -> i64 { 219 let f: i64 = bench_fat_permil(p) 220 let m: i64 = bench_msnf_permil(p) 221 if f == BENCH_INVALID { return BENCH_INVALID } 222 if m == BENCH_INVALID { return BENCH_INVALID } 223 return f + m 224} 225 226// ===== Mix density, and therefore overrun ============================ 227// 228// Specific volume is additive over the components, so the UNAERATED mix 229// density follows from composition alone. Guelph's published model. 230func bench_mix_density_q3(fat_permil: i64, ts_permil: i64) -> i64 { 231 if fat_permil < 0 { return BENCH_INVALID } 232 if ts_permil <= fat_permil { return BENCH_INVALID } 233 if ts_permil >= 1000 { return BENCH_INVALID } 234 let snf: i64 = ts_permil - fat_permil 235 let water: i64 = 1000 - ts_permil 236 let vfat: i64 = fat_permil * BENCH_SV_FAT_Q3 237 let vsnf: i64 = snf * BENCH_SV_SNF_Q3 238 let vwat: i64 = water * BENCH_SV_WATER_Q3 239 let v_q3: i64 = (vfat + vsnf + vwat) / 1000 240 if v_q3 <= 0 { return BENCH_INVALID } 241 return BENCH_MAGIC_1000000 / v_q3 242} 243 244func bench_mix_density_of(p: *BenchProduct) -> i64 { 245 let f: i64 = bench_fat_permil(p) 246 let t: i64 = bench_total_solids_permil(p) 247 if f == BENCH_INVALID { return BENCH_INVALID } 248 if t == BENCH_INVALID { return BENCH_INVALID } 249 return bench_mix_density_q3(f, t) 250} 251 252// Overrun in permil. 100 permil = 10% more volume than the mix. 253func bench_overrun_permil(mix_q3: i64, product_q3: i64) -> i64 { 254 if product_q3 <= 0 { return BENCH_INVALID } 255 if mix_q3 <= 0 { return BENCH_INVALID } 256 if mix_q3 < product_q3 { return BENCH_INVALID } 257 return mix_q3 * 1000 / product_q3 - 1000 258} 259 260func bench_overrun_of(p: *BenchProduct) -> i64 { 261 let mix: i64 = bench_mix_density_of(p) 262 let prod: i64 = bench_density_q3(p) 263 if mix == BENCH_INVALID { return BENCH_INVALID } 264 if prod == BENCH_INVALID { return BENCH_INVALID } 265 return bench_overrun_permil(mix, prod) 266} 267 268// ★AIR FRACTION IS NOT OVERRUN, AND CONSUMER PRESS ROUTINELY CONFLATES THEM. 269// Overrun is air as a fraction of the MIX; air fraction is air as a fraction 270// of the FINISHED product. 20% air is 25% overrun. Encoding both, with a 271// function that proves they differ, stops the 25% error being imported. 272func bench_air_permil_from_overrun(overrun_permil: i64) -> i64 { 273 if overrun_permil < 0 { return BENCH_INVALID } 274 return overrun_permil * 1000 / (1000 + overrun_permil) 275} 276 277func bench_air_equals_overrun(overrun_permil: i64) -> i64 { 278 if overrun_permil <= 0 { return 1 } 279 return 0 280} 281 282// The overrun figure is DERIVED from a modelled mix density, never published 283// by either brand. Callers must be able to see that. 284func bench_overrun_is_derived() -> i64 { return 1 } 285func bench_net_weight_is_derived(p: *BenchProduct) -> i64 { return p.net_weight_derived } 286 287// Sensitivity band: the mix-density model is the weak input, so report what 288// the answer becomes across a plausible range of mix densities rather than 289// pretending to a point estimate. 290func bench_overrun_band(product_q3: i64, mix_lo_q3: i64, mix_hi_q3: i64, out: *i64) -> i64 { 291 if product_q3 <= 0 { return BENCH_INVALID } 292 if mix_lo_q3 > mix_hi_q3 { return BENCH_INVALID } 293 out[0] = bench_overrun_permil(mix_lo_q3, product_q3) 294 out[1] = bench_overrun_permil(mix_hi_q3, product_q3) 295 return 0 296} 297 298// ===== THE TWO LEGAL FLOORS ========================================== 299 300// Minimum finished density from the 4.5 lb/gal WEIGHT floor. Constant. 301func bench_min_density_weight_q3() -> i64 { 302 let num: i64 = BENCH_FDA_MIN_LB_PER_GAL_Q2 * BENCH_G_PER_LB * 1000 303 let den: i64 = 100 * BENCH_ML_PER_GAL 304 return num / den 305} 306 307// Minimum finished density from the 1.6 lb-solids/gal FOOD SOLIDS floor. 308// Rises without limit as total solids fall -- which is exactly why it can 309// overtake the weight floor. 310func bench_min_density_solids_q3(ts_permil: i64) -> i64 { 311 if ts_permil <= 0 { return BENCH_INVALID } 312 let num: i64 = BENCH_FDA_MIN_FOOD_SOLIDS_Q2 * BENCH_G_PER_LB * 1000 * 1000 313 let den: i64 = 100 * BENCH_ML_PER_GAL * ts_permil 314 if den <= 0 { return BENCH_INVALID } 315 return num / den 316} 317 318func bench_binding_floor(ts_permil: i64) -> i64 { 319 let w: i64 = bench_min_density_weight_q3() 320 let s: i64 = bench_min_density_solids_q3(ts_permil) 321 if s == BENCH_INVALID { return BENCH_FLOOR_NONE } 322 if s > w { return BENCH_FLOOR_SOLIDS } 323 return BENCH_FLOOR_WEIGHT 324} 325 326func bench_min_density_q3(ts_permil: i64) -> i64 { 327 let w: i64 = bench_min_density_weight_q3() 328 let s: i64 = bench_min_density_solids_q3(ts_permil) 329 if s == BENCH_INVALID { return BENCH_INVALID } 330 if s > w { return s } 331 return w 332} 333 334// The total-solids level at which the two floors cross. Computed from the 335// two constants, so it moves if either does. 336func bench_floor_crossover_permil() -> i64 { 337 let w: i64 = bench_min_density_weight_q3() 338 if w <= 0 { return BENCH_INVALID } 339 let num: i64 = BENCH_FDA_MIN_FOOD_SOLIDS_Q2 * BENCH_G_PER_LB * 1000 * 1000 340 let den: i64 = 100 * BENCH_ML_PER_GAL * w 341 if den <= 0 { return BENCH_INVALID } 342 return num / den 343} 344 345// ★THE CORRECTED LAW: the air ceiling honours BOTH floors. 346// !!ROUNDING ORDER IS A SAFETY PROPERTY HERE, AND THE FIRST VERSION OF THIS 347// FUNCTION GOT IT WRONG. It called bench_min_density_q3 and divided by the 348// result -- but that floor is 539.76 g/L and integer division had already 349// truncated it to 539. Dividing by a floor that has been rounded DOWN 350// permits MORE air, so truncating a legal minimum loosens the very 351// constraint it encodes. The error was ~1 percentage point of overrun, in 352// the direction that licenses a non-compliant product. 353// 354// The fix is to never materialise the floor: fold it into one expression so 355// the only rounding is the final one. The floor functions are retained for 356// reporting, where a tenth of a g/L does not decide compliance. 357// 358// **A ROUNDED-DOWN DIVISOR IS A RELAXED CONSTRAINT WHEN THE DIVISOR IS A 359// LEGAL FLOOR. 360 361// Air ceiling from the 4.5 lb/gal weight floor alone, permil, exact. 362func bench_ceiling_weight_permil(mix_q3: i64) -> i64 { 363 if mix_q3 <= 0 { return BENCH_INVALID } 364 let num: i64 = mix_q3 * 100 * BENCH_ML_PER_GAL 365 let den: i64 = BENCH_FDA_MIN_LB_PER_GAL_Q2 * BENCH_G_PER_LB 366 if den <= 0 { return BENCH_INVALID } 367 return num / den - 1000 368} 369 370// Air ceiling from the 1.6 lb-solids/gal floor alone, permil, exact. 371func bench_ceiling_solids_permil(mix_q3: i64, ts_permil: i64) -> i64 { 372 if mix_q3 <= 0 { return BENCH_INVALID } 373 if ts_permil <= 0 { return BENCH_INVALID } 374 let num: i64 = mix_q3 * 100 * BENCH_ML_PER_GAL * ts_permil 375 let den: i64 = BENCH_FDA_MIN_FOOD_SOLIDS_Q2 * BENCH_G_PER_LB * 1000 376 if den <= 0 { return BENCH_INVALID } 377 return num / den - 1000 378} 379 380// THE CORRECTED LAW: the binding ceiling is the LOWER of the two. 381func bench_max_overrun_permil(mix_q3: i64, ts_permil: i64) -> i64 { 382 let w: i64 = bench_ceiling_weight_permil(mix_q3) 383 let s: i64 = bench_ceiling_solids_permil(mix_q3, ts_permil) 384 if w == BENCH_INVALID { return BENCH_INVALID } 385 if s == BENCH_INVALID { return BENCH_INVALID } 386 if s < w { return s } 387 return w 388} 389 390// The SHIPPED one-floor law, reproduced here so the defect can be measured 391// rather than described. Weight floor only -- the food-solids floor absent. 392func bench_max_overrun_weight_only_permil(mix_q3: i64) -> i64 { 393 return bench_ceiling_weight_permil(mix_q3) 394} 395 396// How much MORE air the one-floor law permits than the law allows. Zero 397// above the crossover; positive below it. 398func bench_shipped_law_error_permil(mix_q3: i64, ts_permil: i64) -> i64 { 399 let correct: i64 = bench_max_overrun_permil(mix_q3, ts_permil) 400 let shipped: i64 = bench_max_overrun_weight_only_permil(mix_q3) 401 if correct == BENCH_INVALID { return BENCH_INVALID } 402 if shipped == BENCH_INVALID { return BENCH_INVALID } 403 return shipped - correct 404} 405 406// ★The error direction is what decides whether this is a bug or a rounding 407// choice. It over-permits, so it can license a mislabelled product. 408func bench_shipped_law_over_permits(mix_q3: i64, ts_permil: i64) -> i64 { 409 let e: i64 = bench_shipped_law_error_permil(mix_q3, ts_permil) 410 if e == BENCH_INVALID { return 0 } 411 if e > 0 { return 1 } 412 return 0 413} 414 415// ===== Full standard-of-identity check, all FOUR floors ============== 416 417func bench_solids_lb_per_gal_q2(product_q3: i64, ts_permil: i64) -> i64 { 418 if product_q3 <= 0 { return BENCH_INVALID } 419 if ts_permil <= 0 { return BENCH_INVALID } 420 let g_per_gal: i64 = product_q3 * BENCH_ML_PER_GAL / 1000 421 let solids_g: i64 = g_per_gal * ts_permil / 1000 422 return solids_g * 100 / BENCH_G_PER_LB 423} 424 425func bench_weight_lb_per_gal_q2(product_q3: i64) -> i64 { 426 if product_q3 <= 0 { return BENCH_INVALID } 427 let g_per_gal: i64 = product_q3 * BENCH_ML_PER_GAL / 1000 428 return g_per_gal * 100 / BENCH_G_PER_LB 429} 430 431// Returns a bitmask of FAILING clauses, so a caller learns WHICH floor was 432// missed instead of a bare no. 0 = compliant. 433func bench_fda_failures(p: *BenchProduct) -> i64 { 434 let prod: i64 = bench_density_q3(p) 435 let ts: i64 = bench_total_solids_permil(p) 436 let fat: i64 = bench_fat_permil(p) 437 let tms: i64 = bench_total_milk_solids_permil(p) 438 if prod == BENCH_INVALID { return BENCH_INVALID } 439 var bad: i64 = 0 440 if fat < BENCH_FDA_MIN_MILKFAT_PERMIL { bad = bad | 1 } 441 if tms < BENCH_FDA_MIN_MILK_SOL_PERMIL { bad = bad | 2 } 442 if bench_weight_lb_per_gal_q2(prod) < BENCH_FDA_MIN_LB_PER_GAL_Q2 { bad = bad | 4 } 443 if bench_solids_lb_per_gal_q2(prod, ts) < BENCH_FDA_MIN_FOOD_SOLIDS_Q2 { bad = bad | 8 } 444 return bad 445} 446 447func bench_is_ice_cream(p: *BenchProduct) -> i64 { 448 let bad: i64 = bench_fda_failures(p) 449 if bad == 0 { return 1 } 450 return 0 451} 452 453// ===== MELTDOWN: where the reference is beatable ===================== 454// 455// Liu, Sala & Scholten 2023 (Food Hydrocolloids 138:108466) held fat content 456// and ice fraction CONSTANT and varied only fat destabilisation, so the 457// meltdown difference is cleanly attributable: 458// 459// low destabilisation (0-4% aggregated): first drip 12-18 min, 460// melt rate 21-23 permil/min, 461// 97-99% melted 462// high destabilisation (72-100%): first drip 18-30 min, 463// melt rate 7-12 permil/min, 464// 41-47% melted 465// 466// Herald et al. 2008 measured egg yolk against replacements in a French 467// vanilla and found yolk gave the FASTEST first drip (5 min vs 15 min). 468// Unilever's own US 8,574,654 B2 states that yolk PLASMA destabilises far 469// more powerfully than whole yolk -- i.e. the patent holder documents whole 470// yolk as the weak option. 471// 472// ★So an egg-yolk-only system sits at the LOW-destabilisation end, and the 473// reference product uses egg yolk alone. That is the gap. 474 475const BENCH_DRIP_LOW_DESTAB_MIN: i64 = 12 476const BENCH_DRIP_HIGH_DESTAB_MIN: i64 = 18 477const BENCH_MELTRATE_LOW_DESTAB_PERMIL: i64 = 22 478const BENCH_MELTRATE_HIGH_DESTAB_PERMIL: i64 = 10 479 480// Fat destabilisation band (permil) by emulsifier system. These are class 481// bands read off the cited work, not a continuous dose model. 482func bench_destab_permil(emul: i64) -> i64 { 483 if emul == BENCH_EMUL_NONE { return 20 } 484 if emul == BENCH_EMUL_EGG_YOLK { return 60 } 485 if emul == BENCH_EMUL_MONO_DI { return 400 } 486 if emul == BENCH_EMUL_MONO_DI_PS80 { return 800 } 487 return BENCH_INVALID 488} 489 490func bench_first_drip_min(emul: i64) -> i64 { 491 let d: i64 = bench_destab_permil(emul) 492 if d == BENCH_INVALID { return BENCH_INVALID } 493 if d >= 500 { return BENCH_DRIP_HIGH_DESTAB_MIN } 494 return BENCH_DRIP_LOW_DESTAB_MIN 495} 496 497func bench_melt_rate_permil_min(emul: i64) -> i64 { 498 let d: i64 = bench_destab_permil(emul) 499 if d == BENCH_INVALID { return BENCH_INVALID } 500 if d >= 500 { return BENCH_MELTRATE_HIGH_DESTAB_PERMIL } 501 return BENCH_MELTRATE_LOW_DESTAB_PERMIL 502} 503 504// Is the reference beatable on meltdown, and by how much? Returns the ratio 505// of melt rates x1000: >1000 means the challenger holds shape longer. 506func bench_meltdown_advantage_q3(ref_emul: i64, challenger_emul: i64) -> i64 { 507 let r: i64 = bench_melt_rate_permil_min(ref_emul) 508 let c: i64 = bench_melt_rate_permil_min(challenger_emul) 509 if r == BENCH_INVALID { return BENCH_INVALID } 510 if c == BENCH_INVALID { return BENCH_INVALID } 511 if c <= 0 { return BENCH_INVALID } 512 return r * 1000 / c 513} 514 515// ⚠THE CHAIN IS TWO CITED RESULTS, NOT A MEASUREMENT OF THE REFERENCE. 516// We have not put a Ben & Jerry's pint on a meltdown rig. The claim is: 517// yolk-only implies low destabilisation (Herald; Unilever patent), and low 518// destabilisation implies fast meltdown (Liu, measured). Sound, and still 519// INFERRED -- so the organ says so rather than letting a reader assume it 520// was weighed. 521func bench_meltdown_claim_is_inferred() -> i64 { return 1 } 522func bench_reference_was_physically_measured() -> i64 { return 0 } 523 524// ===== Stabiliser reality check ====================================== 525// 526// The reference uses guar + carrageenan. Thaiudom & Goff 2003 rank 527// thermodynamic incompatibility with casein as xanthan > guar > LBG, so guar 528// is the second-worst offender for depletion flocculation -- which is 529// precisely why carrageenan appears on that label at all. Carrageenan is 530// not a thickener here; it is the counter-agent for the primary gum's own 531// side effect. 532func bench_needs_secondary_colloid(primary_gum_permil: i64) -> i64 { 533 if primary_gum_permil <= 0 { return 0 } 534 return 1 535} 536 537func bench_reference_uses_lbg() -> i64 { return 0 } 538func bench_reference_uses_added_emulsifier() -> i64 { return 0 }