@cortex-js/compute-engine 0.56.0 → 0.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. package/dist/compile.esm.js +1137 -92
  2. package/dist/compile.min.esm.js +261 -61
  3. package/dist/compile.min.umd.cjs +262 -62
  4. package/dist/compile.umd.cjs +1137 -92
  5. package/dist/compute-engine.esm.js +1751 -176
  6. package/dist/compute-engine.min.esm.js +273 -73
  7. package/dist/compute-engine.min.umd.cjs +272 -72
  8. package/dist/compute-engine.umd.cjs +1751 -176
  9. package/dist/core.esm.js +1750 -175
  10. package/dist/core.min.esm.js +271 -71
  11. package/dist/core.min.umd.cjs +271 -71
  12. package/dist/core.umd.cjs +1750 -175
  13. package/dist/interval.esm.js +357 -28
  14. package/dist/interval.min.esm.js +6 -6
  15. package/dist/interval.min.umd.cjs +6 -6
  16. package/dist/interval.umd.cjs +357 -28
  17. package/dist/latex-syntax.esm.js +398 -28
  18. package/dist/latex-syntax.min.esm.js +6 -6
  19. package/dist/latex-syntax.min.umd.cjs +6 -6
  20. package/dist/latex-syntax.umd.cjs +398 -28
  21. package/dist/math-json.esm.js +2 -2
  22. package/dist/math-json.min.esm.js +2 -2
  23. package/dist/math-json.min.umd.cjs +2 -2
  24. package/dist/math-json.umd.cjs +2 -2
  25. package/dist/numerics.esm.js +38 -3
  26. package/dist/numerics.min.esm.js +3 -3
  27. package/dist/numerics.min.umd.cjs +4 -4
  28. package/dist/numerics.umd.cjs +38 -3
  29. package/dist/types/big-decimal/big-decimal.d.ts +1 -1
  30. package/dist/types/big-decimal/index.d.ts +1 -1
  31. package/dist/types/big-decimal/transcendentals.d.ts +1 -1
  32. package/dist/types/big-decimal/utils.d.ts +1 -1
  33. package/dist/types/common/ansi-codes.d.ts +1 -1
  34. package/dist/types/common/configuration-change.d.ts +1 -1
  35. package/dist/types/common/fuzzy-string-match.d.ts +1 -1
  36. package/dist/types/common/grapheme-splitter.d.ts +1 -1
  37. package/dist/types/common/interruptible.d.ts +1 -1
  38. package/dist/types/common/one-of.d.ts +1 -1
  39. package/dist/types/common/signals.d.ts +1 -1
  40. package/dist/types/common/type/ast-nodes.d.ts +1 -1
  41. package/dist/types/common/type/boxed-type.d.ts +1 -1
  42. package/dist/types/common/type/lexer.d.ts +1 -1
  43. package/dist/types/common/type/parse.d.ts +1 -1
  44. package/dist/types/common/type/parser.d.ts +1 -1
  45. package/dist/types/common/type/primitive.d.ts +1 -1
  46. package/dist/types/common/type/reduce.d.ts +1 -1
  47. package/dist/types/common/type/serialize.d.ts +1 -1
  48. package/dist/types/common/type/subtype.d.ts +1 -1
  49. package/dist/types/common/type/type-builder.d.ts +1 -1
  50. package/dist/types/common/type/types.d.ts +1 -1
  51. package/dist/types/common/type/utils.d.ts +1 -1
  52. package/dist/types/common/utils.d.ts +1 -1
  53. package/dist/types/compile.d.ts +1 -1
  54. package/dist/types/compute-engine/assume.d.ts +1 -1
  55. package/dist/types/compute-engine/boxed-expression/abstract-boxed-expression.d.ts +8 -1
  56. package/dist/types/compute-engine/boxed-expression/apply.d.ts +1 -1
  57. package/dist/types/compute-engine/boxed-expression/arithmetic-add.d.ts +1 -1
  58. package/dist/types/compute-engine/boxed-expression/arithmetic-mul-div.d.ts +1 -1
  59. package/dist/types/compute-engine/boxed-expression/arithmetic-power.d.ts +1 -1
  60. package/dist/types/compute-engine/boxed-expression/ascii-math.d.ts +1 -1
  61. package/dist/types/compute-engine/boxed-expression/box.d.ts +1 -1
  62. package/dist/types/compute-engine/boxed-expression/boxed-dictionary.d.ts +1 -1
  63. package/dist/types/compute-engine/boxed-expression/boxed-function.d.ts +1 -1
  64. package/dist/types/compute-engine/boxed-expression/boxed-number.d.ts +1 -1
  65. package/dist/types/compute-engine/boxed-expression/boxed-operator-definition.d.ts +7 -1
  66. package/dist/types/compute-engine/boxed-expression/boxed-patterns.d.ts +1 -1
  67. package/dist/types/compute-engine/boxed-expression/boxed-string.d.ts +1 -1
  68. package/dist/types/compute-engine/boxed-expression/boxed-symbol.d.ts +1 -1
  69. package/dist/types/compute-engine/boxed-expression/boxed-tensor.d.ts +1 -1
  70. package/dist/types/compute-engine/boxed-expression/boxed-value-definition.d.ts +1 -1
  71. package/dist/types/compute-engine/boxed-expression/cache.d.ts +1 -1
  72. package/dist/types/compute-engine/boxed-expression/canonical-utils.d.ts +1 -1
  73. package/dist/types/compute-engine/boxed-expression/canonical.d.ts +1 -1
  74. package/dist/types/compute-engine/boxed-expression/compare.d.ts +1 -1
  75. package/dist/types/compute-engine/boxed-expression/constants.d.ts +1 -1
  76. package/dist/types/compute-engine/boxed-expression/expand.d.ts +1 -1
  77. package/dist/types/compute-engine/boxed-expression/expression-map.d.ts +1 -1
  78. package/dist/types/compute-engine/boxed-expression/factor.d.ts +1 -1
  79. package/dist/types/compute-engine/boxed-expression/flatten.d.ts +1 -1
  80. package/dist/types/compute-engine/boxed-expression/hold.d.ts +1 -1
  81. package/dist/types/compute-engine/boxed-expression/inequality-bounds.d.ts +22 -10
  82. package/dist/types/compute-engine/boxed-expression/init-lazy-refs.d.ts +1 -1
  83. package/dist/types/compute-engine/boxed-expression/invisible-operator.d.ts +1 -1
  84. package/dist/types/compute-engine/boxed-expression/match.d.ts +1 -1
  85. package/dist/types/compute-engine/boxed-expression/negate.d.ts +1 -1
  86. package/dist/types/compute-engine/boxed-expression/numerics.d.ts +1 -1
  87. package/dist/types/compute-engine/boxed-expression/order.d.ts +1 -1
  88. package/dist/types/compute-engine/boxed-expression/pattern-utils.d.ts +1 -1
  89. package/dist/types/compute-engine/boxed-expression/polynomial-degree.d.ts +1 -1
  90. package/dist/types/compute-engine/boxed-expression/polynomials.d.ts +1 -1
  91. package/dist/types/compute-engine/boxed-expression/predicates.d.ts +1 -1
  92. package/dist/types/compute-engine/boxed-expression/rules.d.ts +1 -1
  93. package/dist/types/compute-engine/boxed-expression/serialize.d.ts +1 -1
  94. package/dist/types/compute-engine/boxed-expression/sgn.d.ts +1 -1
  95. package/dist/types/compute-engine/boxed-expression/simplify.d.ts +1 -1
  96. package/dist/types/compute-engine/boxed-expression/solve-linear-system.d.ts +1 -1
  97. package/dist/types/compute-engine/boxed-expression/solve.d.ts +1 -1
  98. package/dist/types/compute-engine/boxed-expression/stochastic-equal.d.ts +1 -1
  99. package/dist/types/compute-engine/boxed-expression/trigonometry.d.ts +1 -1
  100. package/dist/types/compute-engine/boxed-expression/type-guards.d.ts +1 -1
  101. package/dist/types/compute-engine/boxed-expression/utils.d.ts +1 -1
  102. package/dist/types/compute-engine/boxed-expression/validate.d.ts +1 -1
  103. package/dist/types/compute-engine/collection-utils.d.ts +1 -1
  104. package/dist/types/compute-engine/compilation/base-compiler.d.ts +62 -6
  105. package/dist/types/compute-engine/compilation/compile-expression.d.ts +1 -1
  106. package/dist/types/compute-engine/compilation/constant-folding.d.ts +1 -1
  107. package/dist/types/compute-engine/compilation/glsl-target.d.ts +1 -1
  108. package/dist/types/compute-engine/compilation/gpu-target.d.ts +44 -1
  109. package/dist/types/compute-engine/compilation/interval-javascript-target.d.ts +1 -1
  110. package/dist/types/compute-engine/compilation/javascript-target.d.ts +1 -1
  111. package/dist/types/compute-engine/compilation/python-target.d.ts +1 -1
  112. package/dist/types/compute-engine/compilation/types.d.ts +1 -1
  113. package/dist/types/compute-engine/compilation/wgsl-target.d.ts +1 -1
  114. package/dist/types/compute-engine/cost-function.d.ts +1 -1
  115. package/dist/types/compute-engine/engine-assumptions.d.ts +1 -1
  116. package/dist/types/compute-engine/engine-cache.d.ts +1 -1
  117. package/dist/types/compute-engine/engine-common-symbols.d.ts +1 -1
  118. package/dist/types/compute-engine/engine-compilation-targets.d.ts +1 -1
  119. package/dist/types/compute-engine/engine-configuration-lifecycle.d.ts +1 -1
  120. package/dist/types/compute-engine/engine-declarations.d.ts +1 -1
  121. package/dist/types/compute-engine/engine-expression-entrypoints.d.ts +1 -1
  122. package/dist/types/compute-engine/engine-extension-contracts.d.ts +1 -1
  123. package/dist/types/compute-engine/engine-library-bootstrap.d.ts +1 -1
  124. package/dist/types/compute-engine/engine-numeric-configuration.d.ts +1 -1
  125. package/dist/types/compute-engine/engine-runtime-state.d.ts +4 -1
  126. package/dist/types/compute-engine/engine-scope.d.ts +1 -1
  127. package/dist/types/compute-engine/engine-sequences.d.ts +1 -1
  128. package/dist/types/compute-engine/engine-simplification-rules.d.ts +1 -1
  129. package/dist/types/compute-engine/engine-startup-coordinator.d.ts +1 -1
  130. package/dist/types/compute-engine/engine-type-resolver.d.ts +1 -1
  131. package/dist/types/compute-engine/engine-validation-entrypoints.d.ts +1 -1
  132. package/dist/types/compute-engine/free-functions.d.ts +1 -1
  133. package/dist/types/compute-engine/function-utils.d.ts +1 -1
  134. package/dist/types/compute-engine/global-types.d.ts +1 -1
  135. package/dist/types/compute-engine/index.d.ts +18 -2
  136. package/dist/types/compute-engine/interval/arithmetic.d.ts +1 -1
  137. package/dist/types/compute-engine/interval/comparison.d.ts +1 -1
  138. package/dist/types/compute-engine/interval/elementary.d.ts +1 -1
  139. package/dist/types/compute-engine/interval/index.d.ts +1 -1
  140. package/dist/types/compute-engine/interval/trigonometric.d.ts +1 -1
  141. package/dist/types/compute-engine/interval/types.d.ts +1 -1
  142. package/dist/types/compute-engine/interval/util.d.ts +1 -1
  143. package/dist/types/compute-engine/latex-syntax/dictionary/default-dictionary.d.ts +1 -1
  144. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-algebra.d.ts +1 -1
  145. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-arithmetic.d.ts +1 -1
  146. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-calculus.d.ts +1 -1
  147. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-colors.d.ts +1 -1
  148. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-complex.d.ts +1 -1
  149. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-core.d.ts +1 -1
  150. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-linear-algebra.d.ts +1 -1
  151. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-logic.d.ts +1 -1
  152. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-other.d.ts +1 -1
  153. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-relational-operators.d.ts +1 -1
  154. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-sets.d.ts +1 -1
  155. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-statistics.d.ts +1 -1
  156. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-symbols.d.ts +1 -1
  157. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-trigonometry.d.ts +1 -1
  158. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-units.d.ts +1 -1
  159. package/dist/types/compute-engine/latex-syntax/dictionary/definitions.d.ts +1 -1
  160. package/dist/types/compute-engine/latex-syntax/dictionary/indexed-types.d.ts +1 -1
  161. package/dist/types/compute-engine/latex-syntax/latex-syntax.d.ts +1 -1
  162. package/dist/types/compute-engine/latex-syntax/parse-number.d.ts +1 -1
  163. package/dist/types/compute-engine/latex-syntax/parse-symbol.d.ts +1 -1
  164. package/dist/types/compute-engine/latex-syntax/parse.d.ts +1 -1
  165. package/dist/types/compute-engine/latex-syntax/serialize-dms.d.ts +1 -1
  166. package/dist/types/compute-engine/latex-syntax/serialize-number.d.ts +1 -1
  167. package/dist/types/compute-engine/latex-syntax/serializer-style.d.ts +1 -1
  168. package/dist/types/compute-engine/latex-syntax/serializer.d.ts +1 -1
  169. package/dist/types/compute-engine/latex-syntax/tokenizer.d.ts +1 -1
  170. package/dist/types/compute-engine/latex-syntax/types.d.ts +40 -1
  171. package/dist/types/compute-engine/latex-syntax/utils.d.ts +1 -1
  172. package/dist/types/compute-engine/library/arithmetic.d.ts +1 -1
  173. package/dist/types/compute-engine/library/calculus.d.ts +1 -1
  174. package/dist/types/compute-engine/library/collections.d.ts +5 -3
  175. package/dist/types/compute-engine/library/colors.d.ts +1 -1
  176. package/dist/types/compute-engine/library/combinatorics.d.ts +1 -1
  177. package/dist/types/compute-engine/library/complex.d.ts +1 -1
  178. package/dist/types/compute-engine/library/control-structures.d.ts +1 -1
  179. package/dist/types/compute-engine/library/core.d.ts +1 -1
  180. package/dist/types/compute-engine/library/fractals.d.ts +1 -1
  181. package/dist/types/compute-engine/library/library.d.ts +1 -1
  182. package/dist/types/compute-engine/library/linear-algebra.d.ts +1 -1
  183. package/dist/types/compute-engine/library/logic-analysis.d.ts +1 -1
  184. package/dist/types/compute-engine/library/logic.d.ts +1 -1
  185. package/dist/types/compute-engine/library/number-theory.d.ts +1 -1
  186. package/dist/types/compute-engine/library/polynomials.d.ts +1 -1
  187. package/dist/types/compute-engine/library/quantity-arithmetic.d.ts +1 -1
  188. package/dist/types/compute-engine/library/random-expression.d.ts +1 -1
  189. package/dist/types/compute-engine/library/relational-operator.d.ts +1 -1
  190. package/dist/types/compute-engine/library/sets.d.ts +1 -1
  191. package/dist/types/compute-engine/library/statistics.d.ts +1 -1
  192. package/dist/types/compute-engine/library/trigonometry.d.ts +1 -1
  193. package/dist/types/compute-engine/library/type-handlers.d.ts +1 -1
  194. package/dist/types/compute-engine/library/unit-data.d.ts +1 -1
  195. package/dist/types/compute-engine/library/units.d.ts +1 -1
  196. package/dist/types/compute-engine/library/utils.d.ts +1 -1
  197. package/dist/types/compute-engine/numeric-value/big-numeric-value.d.ts +1 -1
  198. package/dist/types/compute-engine/numeric-value/exact-numeric-value.d.ts +1 -1
  199. package/dist/types/compute-engine/numeric-value/machine-numeric-value.d.ts +1 -1
  200. package/dist/types/compute-engine/numeric-value/types.d.ts +1 -1
  201. package/dist/types/compute-engine/numerics/bigint.d.ts +1 -1
  202. package/dist/types/compute-engine/numerics/expression.d.ts +1 -1
  203. package/dist/types/compute-engine/numerics/interval.d.ts +1 -1
  204. package/dist/types/compute-engine/numerics/linear-algebra.d.ts +1 -1
  205. package/dist/types/compute-engine/numerics/monte-carlo.d.ts +1 -1
  206. package/dist/types/compute-engine/numerics/numeric-bigint.d.ts +1 -1
  207. package/dist/types/compute-engine/numerics/numeric-bignum.d.ts +1 -1
  208. package/dist/types/compute-engine/numerics/numeric-complex.d.ts +1 -1
  209. package/dist/types/compute-engine/numerics/numeric.d.ts +1 -1
  210. package/dist/types/compute-engine/numerics/primes.d.ts +1 -1
  211. package/dist/types/compute-engine/numerics/random.d.ts +23 -0
  212. package/dist/types/compute-engine/numerics/rationals.d.ts +1 -1
  213. package/dist/types/compute-engine/numerics/richardson.d.ts +1 -1
  214. package/dist/types/compute-engine/numerics/special-functions.d.ts +1 -1
  215. package/dist/types/compute-engine/numerics/statistics.d.ts +1 -1
  216. package/dist/types/compute-engine/numerics/strings.d.ts +1 -1
  217. package/dist/types/compute-engine/numerics/types.d.ts +1 -1
  218. package/dist/types/compute-engine/numerics/unit-data.d.ts +1 -1
  219. package/dist/types/compute-engine/oeis.d.ts +1 -1
  220. package/dist/types/compute-engine/sequence.d.ts +1 -1
  221. package/dist/types/compute-engine/symbolic/antiderivative.d.ts +1 -1
  222. package/dist/types/compute-engine/symbolic/derivative.d.ts +1 -1
  223. package/dist/types/compute-engine/symbolic/distribute.d.ts +1 -1
  224. package/dist/types/compute-engine/symbolic/fu-cost.d.ts +1 -1
  225. package/dist/types/compute-engine/symbolic/fu-transforms.d.ts +1 -1
  226. package/dist/types/compute-engine/symbolic/fu.d.ts +1 -1
  227. package/dist/types/compute-engine/symbolic/logic-utils.d.ts +1 -1
  228. package/dist/types/compute-engine/symbolic/simplify-abs.d.ts +1 -1
  229. package/dist/types/compute-engine/symbolic/simplify-divide.d.ts +1 -1
  230. package/dist/types/compute-engine/symbolic/simplify-factorial.d.ts +1 -1
  231. package/dist/types/compute-engine/symbolic/simplify-hyperbolic.d.ts +1 -1
  232. package/dist/types/compute-engine/symbolic/simplify-infinity.d.ts +1 -1
  233. package/dist/types/compute-engine/symbolic/simplify-log.d.ts +1 -1
  234. package/dist/types/compute-engine/symbolic/simplify-logic.d.ts +1 -1
  235. package/dist/types/compute-engine/symbolic/simplify-power.d.ts +1 -1
  236. package/dist/types/compute-engine/symbolic/simplify-product.d.ts +1 -1
  237. package/dist/types/compute-engine/symbolic/simplify-rules.d.ts +1 -1
  238. package/dist/types/compute-engine/symbolic/simplify-sum.d.ts +1 -1
  239. package/dist/types/compute-engine/symbolic/simplify-trig.d.ts +1 -1
  240. package/dist/types/compute-engine/tensor/tensor-fields.d.ts +1 -1
  241. package/dist/types/compute-engine/tensor/tensors.d.ts +1 -1
  242. package/dist/types/compute-engine/types-definitions.d.ts +1 -1
  243. package/dist/types/compute-engine/types-engine.d.ts +51 -1
  244. package/dist/types/compute-engine/types-evaluation.d.ts +1 -1
  245. package/dist/types/compute-engine/types-expression.d.ts +69 -1
  246. package/dist/types/compute-engine/types-kernel-evaluation.d.ts +1 -1
  247. package/dist/types/compute-engine/types-kernel-serialization.d.ts +1 -1
  248. package/dist/types/compute-engine/types-serialization.d.ts +1 -1
  249. package/dist/types/compute-engine/types.d.ts +1 -1
  250. package/dist/types/compute-engine.d.ts +1 -1
  251. package/dist/types/core.d.ts +1 -1
  252. package/dist/types/interval.d.ts +1 -1
  253. package/dist/types/latex-syntax.d.ts +2 -2
  254. package/dist/types/math-json/symbols.d.ts +1 -1
  255. package/dist/types/math-json/types.d.ts +1 -1
  256. package/dist/types/math-json/utils.d.ts +1 -1
  257. package/dist/types/math-json.d.ts +2 -2
  258. package/dist/types/numerics.d.ts +1 -1
  259. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- /** Compute Engine 0.56.0 */
1
+ /** Compute Engine 0.58.0 */
2
2
 
3
3
  // src/compute-engine/numerics/richardson.ts
4
4
  function extrapolate(f, x0, options = {}) {
@@ -3535,7 +3535,42 @@ function widen2(a, b) {
3535
3535
  if (b === "nothing") return a;
3536
3536
  if (isSubtype(a, b)) return b;
3537
3537
  if (isSubtype(b, a)) return a;
3538
- return superType(a, b);
3538
+ const sup = superType(a, b);
3539
+ if (LOSSY_SUPERTYPE.has(sup)) return unionTypes(a, b);
3540
+ return sup;
3541
+ }
3542
+ var LOSSY_SUPERTYPE = /* @__PURE__ */ new Set([
3543
+ "scalar",
3544
+ "value",
3545
+ "function",
3546
+ "expression",
3547
+ "collection",
3548
+ "indexed_collection",
3549
+ "list",
3550
+ "set",
3551
+ "tuple",
3552
+ "record",
3553
+ "dictionary",
3554
+ "map",
3555
+ "any"
3556
+ ]);
3557
+ function unionTypes(a, b) {
3558
+ const members = [];
3559
+ const push = (t) => {
3560
+ if (typeof t === "object" && t.kind === "union") {
3561
+ for (const m of t.types) push(m);
3562
+ return;
3563
+ }
3564
+ const key = typeof t === "string" ? t : JSON.stringify(t);
3565
+ if (!members.some(
3566
+ (m) => (typeof m === "string" ? m : JSON.stringify(m)) === key
3567
+ ))
3568
+ members.push(t);
3569
+ };
3570
+ push(a);
3571
+ push(b);
3572
+ if (members.length === 1) return members[0];
3573
+ return { kind: "union", types: members };
3539
3574
  }
3540
3575
  function narrow(...types) {
3541
3576
  if (types.length === 0) return "nothing";
@@ -3609,7 +3644,7 @@ function collectionElementType(type) {
3609
3644
  if (type.kind === "set") return type.elements;
3610
3645
  if (type.kind === "tuple") return widen(...type.elements.map((x) => x.type));
3611
3646
  if (type.kind === "dictionary")
3612
- return parseType(`tuple<string, ${type.values}>`);
3647
+ return parseType(`tuple<string, ${typeToString(type.values)}>`);
3613
3648
  if (type.kind === "record") {
3614
3649
  return parseType(
3615
3650
  `tuple<string, ${typeToString(widen(...Object.values(type.elements)))}>`
@@ -5178,6 +5213,64 @@ function parseQuantifier(kind) {
5178
5213
  }
5179
5214
 
5180
5215
  // src/compute-engine/latex-syntax/dictionary/definitions-core.ts
5216
+ var COMPONENT_ACCESS_HEADS = {
5217
+ x: "First",
5218
+ y: "Second",
5219
+ z: "Third",
5220
+ real: "Real",
5221
+ re: "Real",
5222
+ imag: "Imaginary",
5223
+ im: "Imaginary",
5224
+ count: "Length",
5225
+ total: "Sum",
5226
+ max: "Max",
5227
+ min: "Min"
5228
+ };
5229
+ function memberHead(name) {
5230
+ return COMPONENT_ACCESS_HEADS[name] ?? null;
5231
+ }
5232
+ function parseComponentAccess(parser, lhs) {
5233
+ parser.skipVisualSpace();
5234
+ if (parser.match("\\operatorname")) {
5235
+ const name = parser.parseStringGroup();
5236
+ if (name === null) return null;
5237
+ const head = memberHead(name.trim());
5238
+ if (head === null) return null;
5239
+ return [head, lhs];
5240
+ }
5241
+ const tok = parser.peek;
5242
+ if (typeof tok === "string" && tok.startsWith("\\")) {
5243
+ const bare = tok.slice(1);
5244
+ const head = memberHead(bare);
5245
+ if (head !== null) {
5246
+ parser.nextToken();
5247
+ return [head, lhs];
5248
+ }
5249
+ return null;
5250
+ }
5251
+ if (typeof tok === "string" && /^[a-zA-Z]$/.test(tok)) {
5252
+ const head = memberHead(tok);
5253
+ if (head === null) return null;
5254
+ parser.nextToken();
5255
+ return [head, lhs];
5256
+ }
5257
+ return null;
5258
+ }
5259
+ function parseWhenRestriction(parser, lhs, close) {
5260
+ parser.addBoundary(close);
5261
+ parser.skipVisualSpace();
5262
+ const cond = parser.parseExpression({ minPrec: 0 });
5263
+ if (cond === null) {
5264
+ parser.removeBoundary();
5265
+ return null;
5266
+ }
5267
+ parser.skipVisualSpace();
5268
+ if (!parser.matchBoundary()) {
5269
+ parser.removeBoundary();
5270
+ return null;
5271
+ }
5272
+ return ["When", lhs, cond];
5273
+ }
5181
5274
  function parseSequence(parser, terminator, lhs, prec, sep) {
5182
5275
  if (terminator && terminator.minPrec >= prec) return null;
5183
5276
  const result = lhs ? [lhs] : ["Nothing"];
@@ -5453,15 +5546,16 @@ var DEFINITIONS_CORE = [
5453
5546
  precedence: ASSIGNMENT_PRECEDENCE,
5454
5547
  parse: parseAssign
5455
5548
  },
5456
- // General colon operator (type annotation, mapping notation)
5457
- // Precedence below assignment (260) so `:=` takes priority,
5458
- // and below arrows (270) so `f: A \to B` parses as `Colon(f, To(A, B))`
5549
+ // General colon operator (type annotation, mapping notation, Desmos piecewise)
5550
+ // Precedence below comparisons (245) so `cond : val` (Desmos compact piecewise)
5551
+ // parses as `Colon(cond, val)`, and below arrows (270) so
5552
+ // `f: A \to B` parses as `Colon(f, To(A, B))`.
5459
5553
  {
5460
5554
  name: "Colon",
5461
5555
  latexTrigger: ":",
5462
5556
  kind: "infix",
5463
5557
  associativity: "right",
5464
- precedence: 250,
5558
+ precedence: 240,
5465
5559
  serialize: (serializer, expr) => joinLatex([
5466
5560
  serializer.serialize(operand(expr, 1)),
5467
5561
  "\\colon",
@@ -5472,7 +5566,7 @@ var DEFINITIONS_CORE = [
5472
5566
  latexTrigger: "\\colon",
5473
5567
  kind: "infix",
5474
5568
  associativity: "right",
5475
- precedence: 250,
5569
+ precedence: 240,
5476
5570
  parse: "Colon"
5477
5571
  },
5478
5572
  {
@@ -5649,6 +5743,15 @@ var DEFINITIONS_CORE = [
5649
5743
  }
5650
5744
  },
5651
5745
  { name: "LatexTokens", serialize: serializeLatexTokens },
5746
+ // Component-access postfix: expr.member (C3)
5747
+ // The '.' trigger is consumed before the parse function is called.
5748
+ // Precedence 850 > 810 (At/indexing) so .x chains tightly.
5749
+ {
5750
+ kind: "postfix",
5751
+ precedence: 850,
5752
+ latexTrigger: ["."],
5753
+ parse: parseComponentAccess
5754
+ },
5652
5755
  {
5653
5756
  name: "At",
5654
5757
  kind: "postfix",
@@ -5669,6 +5772,29 @@ var DEFINITIONS_CORE = [
5669
5772
  latexTrigger: ["\\left", "\\lbrack"],
5670
5773
  parse: parseAt("\\right", "\\rbrack")
5671
5774
  },
5775
+ // When-restriction: `expr\left\{cond\right\}` → `When(expr, cond)` (D3)
5776
+ {
5777
+ name: "When",
5778
+ kind: "postfix",
5779
+ precedence: 800,
5780
+ latexTrigger: ["\\left", "\\{"],
5781
+ parse: (parser, lhs) => parseWhenRestriction(parser, lhs, ["\\right", "\\}"]),
5782
+ serialize: (serializer, expr) => {
5783
+ const e = operand(expr, 1);
5784
+ const cond = operand(expr, 2);
5785
+ if (!e || !cond) return "";
5786
+ const clauses = operator(cond) === "And" ? operands(cond) ?? [] : [cond];
5787
+ const inner = clauses.map((c) => `\\left\\{${serializer.serialize(c)}\\right\\}`).join("");
5788
+ return `${serializer.serialize(e)}${inner}`;
5789
+ }
5790
+ },
5791
+ // When-restriction: bare `expr\{cond\}` → `When(expr, cond)`
5792
+ {
5793
+ kind: "postfix",
5794
+ precedence: 800,
5795
+ latexTrigger: ["\\{"],
5796
+ parse: (parser, lhs) => parseWhenRestriction(parser, lhs, ["\\}"])
5797
+ },
5672
5798
  {
5673
5799
  kind: "postfix",
5674
5800
  latexTrigger: ["_"],
@@ -5751,6 +5877,29 @@ var DEFINITIONS_CORE = [
5751
5877
  return "";
5752
5878
  }
5753
5879
  },
5880
+ // Additional triggers for Range: `...`, `\ldots`, and `\dots` are
5881
+ // equivalent to `..` when used as infix operators (e.g. `[1...9]`).
5882
+ // No `name` field here — names must be unique per the dictionary rules;
5883
+ // the first Range entry owns the name. When there is no LHS the symbol
5884
+ // entries near the top of the file still fire (ContinuationPlaceholder).
5885
+ {
5886
+ latexTrigger: [".", ".", "."],
5887
+ kind: "infix",
5888
+ precedence: 800,
5889
+ parse: parseRange
5890
+ },
5891
+ {
5892
+ latexTrigger: ["\\ldots"],
5893
+ kind: "infix",
5894
+ precedence: 800,
5895
+ parse: parseRange
5896
+ },
5897
+ {
5898
+ latexTrigger: ["\\dots"],
5899
+ kind: "infix",
5900
+ precedence: 800,
5901
+ parse: parseRange
5902
+ },
5754
5903
  {
5755
5904
  latexTrigger: [";"],
5756
5905
  kind: "infix",
@@ -5935,13 +6084,24 @@ var DEFINITIONS_CORE = [
5935
6084
  const args = operands(expr);
5936
6085
  if (!args || args.length < 2) return "";
5937
6086
  const body = args[0];
5938
- const indexing = args[1];
5939
- if (operator(indexing) === "Element") {
5940
- const index = operand(indexing, 1);
5941
- const range2 = operand(indexing, 2);
5942
- if (operator(range2) === "Range") {
5943
- const lo = operand(range2, 1);
5944
- const hi = operand(range2, 2);
6087
+ const elements = args.slice(1);
6088
+ const allElements = elements.every((e) => operator(e) === "Element");
6089
+ if (!allElements) {
6090
+ return joinLatex([
6091
+ "\\operatorname{Loop}(",
6092
+ serializer.serialize(body),
6093
+ ", ",
6094
+ serializer.serialize(elements[0]),
6095
+ ")"
6096
+ ]);
6097
+ }
6098
+ if (elements.length === 1) {
6099
+ const elem = elements[0];
6100
+ const index = operand(elem, 1);
6101
+ const coll = operand(elem, 2);
6102
+ if (operator(coll) === "Range") {
6103
+ const lo = operand(coll, 1);
6104
+ const hi = operand(coll, 2);
5945
6105
  return joinLatex([
5946
6106
  "\\text{for }",
5947
6107
  serializer.serialize(index),
@@ -5953,13 +6113,27 @@ var DEFINITIONS_CORE = [
5953
6113
  serializer.serialize(body)
5954
6114
  ]);
5955
6115
  }
6116
+ return joinLatex([
6117
+ serializer.serialize(body),
6118
+ " \\operatorname{for} ",
6119
+ serializer.serialize(index),
6120
+ " = ",
6121
+ serializer.serialize(coll)
6122
+ ]);
5956
6123
  }
6124
+ const bindings = elements.map((elem) => {
6125
+ const name = operand(elem, 1);
6126
+ const coll = operand(elem, 2);
6127
+ return joinLatex([
6128
+ serializer.serialize(name),
6129
+ " = ",
6130
+ serializer.serialize(coll)
6131
+ ]);
6132
+ }).join(", ");
5957
6133
  return joinLatex([
5958
- "\\operatorname{Loop}(",
5959
6134
  serializer.serialize(body),
5960
- ", ",
5961
- serializer.serialize(indexing),
5962
- ")"
6135
+ " \\operatorname{for} ",
6136
+ bindings
5963
6137
  ]);
5964
6138
  }
5965
6139
  },
@@ -5992,6 +6166,18 @@ var DEFINITIONS_CORE = [
5992
6166
  precedence: 245,
5993
6167
  parse: (parser, until) => parseForExpression(parser, until)
5994
6168
  },
6169
+ // \operatorname{for} as postfix infix (list comprehension):
6170
+ // `body \operatorname{for} x = L_1, y = L_2`
6171
+ // Precedence 19 — just below comma (20) so the body is allowed to use
6172
+ // any operator (including comma sequencing) up to the keyword, and the
6173
+ // bindings can be comma-separated below us.
6174
+ {
6175
+ symbolTrigger: "for",
6176
+ kind: "infix",
6177
+ associativity: "none",
6178
+ precedence: 19,
6179
+ parse: (parser, lhs, until) => parseForComprehension(parser, lhs, until)
6180
+ },
5995
6181
  // \operatorname{break}
5996
6182
  {
5997
6183
  symbolTrigger: "break",
@@ -6196,7 +6382,10 @@ var DEFINITIONS_CORE = [
6196
6382
  if (!sym2 || !parser.getSymbolType(sym2).matches("function")) return null;
6197
6383
  parser.addBoundary([")"]);
6198
6384
  const expr = parser.parseExpression(until);
6199
- if (!parser.matchBoundary()) return null;
6385
+ if (!parser.matchBoundary()) {
6386
+ parser.removeBoundary();
6387
+ return null;
6388
+ }
6200
6389
  if (!parser.match("<}>")) return null;
6201
6390
  return ["Derivative", lhs, expr];
6202
6391
  }
@@ -6637,7 +6826,12 @@ function parseBrackets(parser, body) {
6637
6826
  if (isEmptySequence(body)) return ["List"];
6638
6827
  const h = operator(body);
6639
6828
  if (h === "Range" || h === "Linspace") return body;
6640
- if (h === "Sequence") return ["List", ...operands(body)];
6829
+ if (h === "Sequence") {
6830
+ const elems = operands(body);
6831
+ const inferred = tryInferRangeFromElements(elems, parser);
6832
+ if (inferred) return inferred;
6833
+ return ["List", ...elems];
6834
+ }
6641
6835
  if (h === "Delimiter") {
6642
6836
  const delim = stringValue(operand(body, 2)) ?? "...";
6643
6837
  if (delim === ";" || delim === ".;.") {
@@ -6650,12 +6844,37 @@ function parseBrackets(parser, body) {
6650
6844
  }
6651
6845
  if (delim === "," || delim === ".,.") {
6652
6846
  body = operand(body, 1);
6653
- if (operator(body) === "Sequence") return ["List", ...operands(body)];
6847
+ if (operator(body) === "Sequence") {
6848
+ const elems = operands(body);
6849
+ const inferred = tryInferRangeFromElements(elems, parser);
6850
+ if (inferred) return inferred;
6851
+ return ["List", ...elems];
6852
+ }
6654
6853
  return ["List", body ?? "Nothing"];
6655
6854
  }
6656
6855
  }
6657
6856
  return ["List", body];
6658
6857
  }
6858
+ function tryInferRangeFromElements(elems, parser) {
6859
+ if (elems.length < 4) return null;
6860
+ const penultimate = elems[elems.length - 2];
6861
+ if (symbol(penultimate) !== "ContinuationPlaceholder") return null;
6862
+ const samples = elems.slice(0, -2);
6863
+ const endExpr = elems[elems.length - 1];
6864
+ if (samples.length < 2) return null;
6865
+ const sampleNums = samples.map(machineValue);
6866
+ if (sampleNums.some((n) => n === null)) return null;
6867
+ const nums = sampleNums;
6868
+ const step = nums[nums.length - 1] - nums[nums.length - 2];
6869
+ const tol = parser.options.tolerance;
6870
+ if (Math.abs(step) < tol)
6871
+ return parser.error("degenerate-range-step", parser.index);
6872
+ for (let i = 1; i < nums.length; i++) {
6873
+ if (Math.abs(nums[i] - nums[i - 1] - step) > tol)
6874
+ return parser.error("inconsistent-range-samples", parser.index);
6875
+ }
6876
+ return ["Range", nums[0], endExpr, step];
6877
+ }
6659
6878
  function serializeList(serializer, expr) {
6660
6879
  if (nops(expr) > 1 && operands(expr).every((x) => {
6661
6880
  const op = operator(x);
@@ -6907,6 +7126,38 @@ function parseForExpression(parser, until) {
6907
7126
  ["Element", index, ["Range", lower, upper]]
6908
7127
  ];
6909
7128
  }
7129
+ function parseForComprehension(parser, lhs, until) {
7130
+ const bindingTerminator = {
7131
+ minPrec: 21,
7132
+ // Above comma (20) and ; (19), so `x = L_1` is captured whole
7133
+ condition: (p) => {
7134
+ if (until?.condition?.(p)) return true;
7135
+ const saved = p.index;
7136
+ p.skipVisualSpace();
7137
+ const isComma = p.peek === ",";
7138
+ p.index = saved;
7139
+ if (isComma) return true;
7140
+ if (peekKeyword(p, "where")) return true;
7141
+ if (peekKeyword(p, "with")) return true;
7142
+ return false;
7143
+ }
7144
+ };
7145
+ const elements = [];
7146
+ do {
7147
+ parser.skipVisualSpace();
7148
+ const binding = parser.parseExpression(bindingTerminator);
7149
+ if (binding === null) break;
7150
+ const op = operator(binding);
7151
+ if (op !== "Equal" && op !== "Assign") return null;
7152
+ const name = operand(binding, 1);
7153
+ const list = operand(binding, 2);
7154
+ if (!name || !list) return null;
7155
+ elements.push(["Element", name, list]);
7156
+ parser.skipVisualSpace();
7157
+ } while (parser.match(","));
7158
+ if (elements.length === 0) return null;
7159
+ return ["Loop", lhs, ...elements];
7160
+ }
6910
7161
  function parseWhereExpression(parser, lhs, until) {
6911
7162
  const bindingTerminator = {
6912
7163
  minPrec: 21,
@@ -6929,6 +7180,25 @@ function parseWhereExpression(parser, lhs, until) {
6929
7180
  parser.skipVisualSpace();
6930
7181
  } while (parser.match(","));
6931
7182
  if (bindings.length === 0) return null;
7183
+ const forStart = parser.index;
7184
+ if (matchKeyword(parser, "for")) {
7185
+ const loop = parseForComprehension(parser, lhs, until);
7186
+ if (loop) {
7187
+ const block2 = [];
7188
+ for (const b of bindings) {
7189
+ const normalized = normalizeLocalAssign(b);
7190
+ if (operator(normalized) === "Assign") {
7191
+ block2.push(["Declare", operand(normalized, 1)]);
7192
+ block2.push(normalized);
7193
+ } else {
7194
+ block2.push(normalized);
7195
+ }
7196
+ }
7197
+ block2.push(loop);
7198
+ return ["Block", ...block2];
7199
+ }
7200
+ parser.index = forStart;
7201
+ }
6932
7202
  const block = [];
6933
7203
  for (const b of bindings) {
6934
7204
  const normalized = normalizeLocalAssign(b);
@@ -7142,6 +7412,17 @@ function parseIntervalBody(body, openLeft, openRight) {
7142
7412
  const upperExpr = openRight ? ["Open", upper] : upper;
7143
7413
  return ["Interval", lowerExpr, upperExpr];
7144
7414
  }
7415
+ var COMPARISON_HEADS = /* @__PURE__ */ new Set([
7416
+ "Less",
7417
+ "LessEqual",
7418
+ "Greater",
7419
+ "GreaterEqual",
7420
+ "Equal",
7421
+ "NotEqual",
7422
+ "And",
7423
+ "Or",
7424
+ "Not"
7425
+ ]);
7145
7426
  var DEFINITIONS_SETS = [
7146
7427
  //
7147
7428
  // Constants
@@ -7400,18 +7681,58 @@ var DEFINITIONS_SETS = [
7400
7681
  closeTrigger: "}",
7401
7682
  parse: (_parser, body) => {
7402
7683
  if (isEmptySequence(body)) return "EmptySet";
7684
+ if (operator(body) == "Delimiter" && stringValue(operand(body, 2)) === ",") {
7685
+ body = operand(body, 1);
7686
+ }
7403
7687
  const h = operator(body);
7404
- if (h === "Divides" || h === "Colon") {
7688
+ if (h === "Divides") {
7405
7689
  const expr = operand(body, 1);
7406
7690
  const condition = operand(body, 2);
7407
7691
  if (expr !== null && condition !== null)
7408
7692
  return ["Set", expr, ["Condition", condition]];
7409
7693
  }
7410
- if (operator(body) == "Delimiter" && stringValue(operand(body, 2)) === ",") {
7411
- body = operand(body, 1);
7694
+ if (h === "Colon") {
7695
+ const lhs = operand(body, 1);
7696
+ const rhs = operand(body, 2);
7697
+ if (lhs !== null && rhs !== null) {
7698
+ const lhsOp = operator(lhs);
7699
+ if (lhsOp !== null && COMPARISON_HEADS.has(lhsOp)) {
7700
+ return ["Which", lhs, rhs];
7701
+ }
7702
+ return ["Set", lhs, ["Condition", rhs]];
7703
+ }
7704
+ }
7705
+ if (h === "Sequence") {
7706
+ const elements = operands(body);
7707
+ const colonElements = elements.filter((el) => operator(el) === "Colon");
7708
+ const allPiecewise = colonElements.length > 0 && colonElements.every((el) => {
7709
+ const lhs = operand(el, 1);
7710
+ const lhsOp = lhs !== null ? operator(lhs) : null;
7711
+ return lhsOp !== null && COMPARISON_HEADS.has(lhsOp);
7712
+ });
7713
+ if (allPiecewise) {
7714
+ const whichOps = [];
7715
+ for (let i = 0; i < elements.length; i++) {
7716
+ const el = elements[i];
7717
+ if (operator(el) === "Colon") {
7718
+ const cond = operand(el, 1);
7719
+ const val = operand(el, 2);
7720
+ if (cond === null || val === null) {
7721
+ return ["Set", ...elements];
7722
+ }
7723
+ whichOps.push(cond, val);
7724
+ } else {
7725
+ if (i !== elements.length - 1) {
7726
+ return ["Set", ...elements];
7727
+ }
7728
+ whichOps.push("True", el);
7729
+ }
7730
+ }
7731
+ return ["Which", ...whichOps];
7732
+ }
7733
+ return ["Set", ...elements];
7412
7734
  }
7413
- if (operator(body) !== "Sequence") return ["Set", body];
7414
- return ["Set", ...operands(body)];
7735
+ return ["Set", body];
7415
7736
  },
7416
7737
  serialize: (serializer, expr) => {
7417
7738
  if (nops(expr) === 2 && operator(operand(expr, 2)) === "Condition") {
@@ -9385,7 +9706,8 @@ function parseTrig(op) {
9385
9706
  minPrec: MULTIPLICATION_PRECEDENCE,
9386
9707
  condition: (parser2) => trigCommands[parser2.peek] || (until?.condition?.(parser2) ?? false)
9387
9708
  });
9388
- const appliedFn = args === null ? fn : typeof fn === "string" ? [fn, ...args] : ["Apply", fn, ...args];
9709
+ const head = fn === "Arctan" && args?.length === 2 ? "Arctan2" : fn;
9710
+ const appliedFn = args === null ? fn : typeof head === "string" ? [head, ...args] : ["Apply", head, ...args];
9389
9711
  return sup === null ? appliedFn : ["Power", appliedFn, sup];
9390
9712
  };
9391
9713
  }
@@ -11508,10 +11830,17 @@ var DEFINITIONS_OTHERS = [
11508
11830
  // The capitalized library entries already exist; these are pure parse
11509
11831
  // aliases so the lowercase names don't land in `unsupported-operator`.
11510
11832
  // ---------------------------------------------------------------------------
11833
+ { latexTrigger: "\\operatorname{count}", parse: "Length" },
11511
11834
  { latexTrigger: "\\operatorname{random}", parse: "Random" },
11512
11835
  { latexTrigger: "\\operatorname{shuffle}", parse: "Shuffle" },
11513
11836
  { latexTrigger: "\\operatorname{repeat}", parse: "Repeat" },
11514
11837
  { latexTrigger: "\\operatorname{join}", parse: "Join" },
11838
+ { latexTrigger: "\\operatorname{range}", parse: "Range" },
11839
+ // Note: `\operatorname{with}` (Desmos's local-binding clause) is intentionally
11840
+ // NOT registered here. Use the math-notation equivalent `\operatorname{where}`
11841
+ // (with `\coloneq` for bindings), or register `with` as a custom dictionary
11842
+ // entry at the integration layer — see the "Desmos-Specific Syntax — Prefer
11843
+ // Custom LaTeX Dictionary" section in COMPUTE_ENGINE.md for a worked example.
11515
11844
  // ---------------------------------------------------------------------------
11516
11845
  // Geometric primitive heads. Registered as known typed heads so consumers
11517
11846
  // can branch on the operator name; CE itself doesn't render them. The
@@ -12702,6 +13031,15 @@ function interval(expr) {
12702
13031
  return void 0;
12703
13032
  }
12704
13033
 
13034
+ // src/compute-engine/numerics/random.ts
13035
+ function deterministicRandom(seed) {
13036
+ const v = Math.sin(seed * 12.9898) * 43758.5453;
13037
+ return v - Math.floor(v);
13038
+ }
13039
+ function nextSeed(seed) {
13040
+ return seed + 0.6180339887498949;
13041
+ }
13042
+
12705
13043
  // src/compute-engine/boxed-expression/canonical-utils.ts
12706
13044
  function canonical(ce, xs, scope) {
12707
13045
  if (xs.every((x) => x.isCanonical)) return xs;
@@ -12751,6 +13089,19 @@ var COLLECTIONS_LIBRARY = {
12751
13089
  indexWhere: void 0
12752
13090
  }
12753
13091
  },
13092
+ Length: {
13093
+ description: "Number of elements in a collection. Returns undefined for non-collections and for infinite collections.",
13094
+ complexity: 4e3,
13095
+ signature: "(any) -> integer",
13096
+ type: () => "integer",
13097
+ evaluate: ([xs], { engine }) => {
13098
+ if (!xs.isCollection) return void 0;
13099
+ if (xs.isEmptyCollection) return engine.Zero;
13100
+ const n = xs.count;
13101
+ if (n === void 0 || !isFinite(n)) return void 0;
13102
+ return engine.number(n);
13103
+ }
13104
+ },
12754
13105
  Tuple: {
12755
13106
  description: "A fixed number of heterogeneous elements",
12756
13107
  complexity: 8200,
@@ -12803,7 +13154,11 @@ var COLLECTIONS_LIBRARY = {
12803
13154
  //
12804
13155
  Range: {
12805
13156
  complexity: 8200,
12806
- signature: "(number, number?, step: number?) -> indexed_collection<integer>",
13157
+ signature: "(number, number?, step: number?) -> indexed_collection<number>",
13158
+ type: (ops) => {
13159
+ const allInt = ops.every((op) => op.isInteger);
13160
+ return allInt ? parseType("indexed_collection<integer>") : parseType("indexed_collection<number>");
13161
+ },
12807
13162
  canonical: (ops, { engine: ce }) => {
12808
13163
  if (ops.length === 0) return null;
12809
13164
  if (ops.length === 1) return ce._fn("Range", [ce.One, ops[0].canonical]);
@@ -12827,19 +13182,26 @@ var COLLECTIONS_LIBRARY = {
12827
13182
  const [lower, upper, step] = range(expr);
12828
13183
  if (step === 0) return 0;
12829
13184
  if (!isFinite(lower) || !isFinite(upper)) return Infinity;
12830
- return 1 + Math.max(0, Math.floor((upper - lower) / step));
13185
+ return Math.max(0, Math.floor((upper - lower) / step) + 1);
12831
13186
  },
12832
13187
  contains: (expr, target) => {
12833
- if (!target.type.matches("integer")) return false;
12834
13188
  const t = target.re;
13189
+ if (!isFinite(t)) return false;
12835
13190
  const [lower, upper, step] = range(expr);
12836
13191
  if (step === 0) return false;
12837
- if (step > 0) return t >= lower && t <= upper;
12838
- return t <= lower && t >= upper;
13192
+ if (step > 0) {
13193
+ if (t < lower || t > upper) return false;
13194
+ } else {
13195
+ if (t > lower || t < upper) return false;
13196
+ }
13197
+ const k = (t - lower) / step;
13198
+ const tol = expr.engine.tolerance;
13199
+ const kRounded = Math.round(k);
13200
+ return kRounded >= 0 && Math.abs(k - kRounded) < tol;
12839
13201
  },
12840
13202
  iterator: (expr) => {
12841
13203
  const [lower, upper, step] = range(expr);
12842
- const maxCount = step === 0 ? 0 : Math.floor((upper - lower) / step) + 1;
13204
+ const maxCount = step === 0 ? 0 : Math.max(0, Math.floor((upper - lower) / step) + 1);
12843
13205
  let index = 1;
12844
13206
  return {
12845
13207
  next: () => {
@@ -12857,7 +13219,9 @@ var COLLECTIONS_LIBRARY = {
12857
13219
  at: (expr, index) => {
12858
13220
  if (typeof index !== "number") return void 0;
12859
13221
  const [lower, upper, step] = range(expr);
12860
- if (index < 1 || index > 1 + (upper - lower) / step) return void 0;
13222
+ if (step === 0) return void 0;
13223
+ const maxCount = Math.max(0, Math.floor((upper - lower) / step) + 1);
13224
+ if (index < 1 || index > maxCount) return void 0;
12861
13225
  return expr.engine.number(lower + step * (index - 1));
12862
13226
  },
12863
13227
  indexWhere: void 0,
@@ -12882,7 +13246,13 @@ var COLLECTIONS_LIBRARY = {
12882
13246
  if (step > 0) return lower <= upper ? "positive" : "negative";
12883
13247
  return lower >= upper ? "positive" : "negative";
12884
13248
  },
12885
- elttype: (_expr) => "finite_integer"
13249
+ elttype: (expr) => {
13250
+ if (!isFunction2(expr)) return "finite_integer";
13251
+ for (let i = 1; i <= expr.nops; i++) {
13252
+ if (!expr[`op${i}`].isInteger) return "finite_real";
13253
+ }
13254
+ return "finite_integer";
13255
+ }
12886
13256
  }
12887
13257
  },
12888
13258
  Interval: {
@@ -12985,10 +13355,12 @@ var COLLECTIONS_LIBRARY = {
12985
13355
  const upper = expr.op2.re;
12986
13356
  let count = expr.op3.re;
12987
13357
  if (!isFinite(count)) count = DEFAULT_LINSPACE_COUNT;
13358
+ count = Math.floor(count);
12988
13359
  if (!isFinite(lower) || !isFinite(upper)) return void 0;
12989
13360
  if (index < 1 || index > count) return void 0;
13361
+ if (count === 1) return expr.engine.number(lower);
12990
13362
  return expr.engine.number(
12991
- lower + (upper - lower) * (index - 1) / count
13363
+ lower + (upper - lower) * (index - 1) / (count - 1)
12992
13364
  );
12993
13365
  },
12994
13366
  iterator: (expr) => {
@@ -13007,6 +13379,8 @@ var COLLECTIONS_LIBRARY = {
13007
13379
  !isFinite(expr.op3.re) ? DEFAULT_LINSPACE_COUNT : expr.op3.re
13008
13380
  );
13009
13381
  }
13382
+ totalCount = Math.floor(totalCount);
13383
+ const denom = totalCount > 1 ? totalCount - 1 : 1;
13010
13384
  let index = 1;
13011
13385
  return {
13012
13386
  next: () => {
@@ -13015,7 +13389,7 @@ var COLLECTIONS_LIBRARY = {
13015
13389
  index += 1;
13016
13390
  return {
13017
13391
  value: expr.engine.number(
13018
- lower + (upper - lower) * (index - 1 - 1) / totalCount
13392
+ lower + (upper - lower) * (index - 1 - 1) / denom
13019
13393
  ),
13020
13394
  done: false
13021
13395
  };
@@ -13031,9 +13405,14 @@ var COLLECTIONS_LIBRARY = {
13031
13405
  if (t < lower || t > upper) return false;
13032
13406
  let count = expr.op3.re;
13033
13407
  if (!isFinite(count)) count = DEFAULT_LINSPACE_COUNT;
13408
+ count = Math.floor(count);
13034
13409
  if (count === 0) return false;
13035
- const step = (upper - lower) / count;
13036
- return (t - lower) % step === 0;
13410
+ if (count === 1) return t === lower;
13411
+ const step = (upper - lower) / (count - 1);
13412
+ const k = (t - lower) / step;
13413
+ const tol = expr.engine.tolerance;
13414
+ const kRounded = Math.round(k);
13415
+ return kRounded >= 0 && kRounded <= count - 1 && Math.abs(k - kRounded) < tol;
13037
13416
  }
13038
13417
  }
13039
13418
  },
@@ -13358,10 +13737,12 @@ var COLLECTIONS_LIBRARY = {
13358
13737
  description: [
13359
13738
  "Access an element of an indexed collection.",
13360
13739
  "If the index is negative, it is counted from the end.",
13361
- "Multiple indices can be provided to access nested collections (e.g., matrices)."
13740
+ "Multiple indices can be provided to access nested collections (e.g., matrices).",
13741
+ "If the index is a finite collection of booleans, returns the elements where the mask is True.",
13742
+ "If the index is a finite collection of integers, returns the elements at those indices."
13362
13743
  ],
13363
13744
  complexity: 8200,
13364
- signature: "(value: indexed_collection, index: (number|string)+) -> unknown",
13745
+ signature: "(value: indexed_collection, index: (number|string|indexed_collection)+) -> unknown",
13365
13746
  type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? collectionElementType(xs.type.type) ?? "any",
13366
13747
  evaluate: (ops, { engine: ce }) => {
13367
13748
  let expr = ops[0];
@@ -13372,12 +13753,39 @@ var COLLECTIONS_LIBRARY = {
13372
13753
  if (!at) return void 0;
13373
13754
  const opAtIndex = ops[index];
13374
13755
  const s = isString(opAtIndex) ? opAtIndex.string : void 0;
13375
- if (s !== void 0) expr = at(expr, s) ?? ce.Nothing;
13376
- else {
13377
- const i = ops[index].re;
13378
- if (!Number.isInteger(i)) return void 0;
13379
- expr = at(expr, i) ?? ce.Nothing;
13756
+ if (s !== void 0) {
13757
+ expr = at(expr, s) ?? ce.Nothing;
13758
+ index += 1;
13759
+ continue;
13760
+ }
13761
+ if (opAtIndex.isCollection && opAtIndex.isFiniteCollection) {
13762
+ const indices = Array.from(opAtIndex.each());
13763
+ const isMask = indices.every((m) => {
13764
+ const name = sym(m);
13765
+ return name === "True" || name === "False";
13766
+ });
13767
+ const picked = [];
13768
+ if (isMask) {
13769
+ indices.forEach((m, i2) => {
13770
+ if (sym(m) !== "True") return;
13771
+ const v = at(expr, i2 + 1);
13772
+ if (v !== void 0) picked.push(v);
13773
+ });
13774
+ } else {
13775
+ for (const m of indices) {
13776
+ const k = m.re;
13777
+ if (!Number.isInteger(k)) return void 0;
13778
+ const v = at(expr, k);
13779
+ if (v !== void 0) picked.push(v);
13780
+ }
13781
+ }
13782
+ expr = ce._fn("List", picked);
13783
+ index += 1;
13784
+ continue;
13380
13785
  }
13786
+ const i = opAtIndex.re;
13787
+ if (!Number.isInteger(i)) return void 0;
13788
+ expr = at(expr, i) ?? ce.Nothing;
13381
13789
  index += 1;
13382
13790
  }
13383
13791
  return expr;
@@ -13388,7 +13796,7 @@ var COLLECTIONS_LIBRARY = {
13388
13796
  description: ["Return `n` elements from a collection."],
13389
13797
  complexity: 8200,
13390
13798
  signature: "(xs: indexed_collection, count: number) -> indexed_collection",
13391
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
13799
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
13392
13800
  evaluate: (ops, { engine, materialization: eager }) => {
13393
13801
  if (!eager) return void 0;
13394
13802
  const takeExpr = engine._fn("Take", ops);
@@ -13435,7 +13843,7 @@ var COLLECTIONS_LIBRARY = {
13435
13843
  description: ["Return the collection without the first n elements."],
13436
13844
  complexity: 8200,
13437
13845
  signature: "(xs: indexed_collection, count: number) -> indexed_collection",
13438
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
13846
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
13439
13847
  collection: {
13440
13848
  isLazy: (_expr) => true,
13441
13849
  count: (expr) => {
@@ -13480,15 +13888,45 @@ var COLLECTIONS_LIBRARY = {
13480
13888
  },
13481
13889
  First: {
13482
13890
  complexity: 8200,
13483
- signature: "(collection) -> any",
13891
+ signature: "(any) -> any",
13484
13892
  type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? "any",
13485
- evaluate: ([xs], { engine: ce }) => xs.at(1) ?? ce.Nothing
13893
+ evaluate: ([xs], { engine: ce }) => {
13894
+ if (!xs.isCollection)
13895
+ return ce.error([
13896
+ "incompatible-type",
13897
+ `'collection'`,
13898
+ xs.type.toString()
13899
+ ]);
13900
+ return xs.at(1) ?? ce.Nothing;
13901
+ }
13486
13902
  },
13487
13903
  Second: {
13488
13904
  complexity: 8200,
13489
- signature: "(collection) -> any",
13905
+ signature: "(any) -> any",
13906
+ type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? "any",
13907
+ evaluate: ([xs], { engine: ce }) => {
13908
+ if (!xs.isCollection)
13909
+ return ce.error([
13910
+ "incompatible-type",
13911
+ `'collection'`,
13912
+ xs.type.toString()
13913
+ ]);
13914
+ return xs.at(2) ?? ce.Nothing;
13915
+ }
13916
+ },
13917
+ Third: {
13918
+ complexity: 8200,
13919
+ signature: "(any) -> any",
13490
13920
  type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? "any",
13491
- evaluate: ([xs], { engine: ce }) => xs.at(2) ?? ce.Nothing
13921
+ evaluate: ([xs], { engine: ce }) => {
13922
+ if (!xs.isCollection)
13923
+ return ce.error([
13924
+ "incompatible-type",
13925
+ `'collection'`,
13926
+ xs.type.toString()
13927
+ ]);
13928
+ return xs.at(3) ?? ce.Nothing;
13929
+ }
13492
13930
  },
13493
13931
  Last: {
13494
13932
  complexity: 8200,
@@ -13601,7 +14039,9 @@ var COLLECTIONS_LIBRARY = {
13601
14039
  ],
13602
14040
  complexity: 8200,
13603
14041
  signature: "(value: indexed_collection, start: number, end: number) -> list",
13604
- type: ([xs]) => parseType(`list<${collectionElementType(xs.type.type)}>`),
14042
+ type: ([xs]) => parseType(
14043
+ `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`
14044
+ ),
13605
14045
  collection: {
13606
14046
  isLazy: (_expr) => true,
13607
14047
  count: (expr) => {
@@ -13933,16 +14373,26 @@ var COLLECTIONS_LIBRARY = {
13933
14373
  },
13934
14374
  // Randomize the order of the elements in the collection.
13935
14375
  Shuffle: {
13936
- description: "Randomize the order of the elements in the collection.",
14376
+ description: "Randomize the order of the elements in the collection. With an optional `seed` argument, the shuffle is deterministic.",
13937
14377
  complexity: 8200,
13938
- signature: "(indexed_collection) -> indexed_collection",
14378
+ signature: "(indexed_collection, real?) -> indexed_collection",
13939
14379
  type: (ops) => ops[0].type,
13940
- evaluate: ([xs], { engine: ce }) => {
14380
+ evaluate: ([xs, seedOp], { engine: ce }) => {
13941
14381
  if (!xs.isFiniteCollection) return void 0;
13942
14382
  const data = Array.from(xs.each());
13943
- for (let i = data.length - 1; i > 0; i--) {
13944
- const j = Math.floor(Math.random() * (i + 1));
13945
- [data[i], data[j]] = [data[j], data[i]];
14383
+ const seed = seedOp?.re;
14384
+ if (seed !== void 0 && !Number.isNaN(seed)) {
14385
+ let s = seed;
14386
+ for (let i = data.length - 1; i > 0; i--) {
14387
+ const j = Math.floor(deterministicRandom(s) * (i + 1));
14388
+ [data[i], data[j]] = [data[j], data[i]];
14389
+ s = nextSeed(s);
14390
+ }
14391
+ } else {
14392
+ for (let i = data.length - 1; i > 0; i--) {
14393
+ const j = Math.floor(Math.random() * (i + 1));
14394
+ [data[i], data[j]] = [data[j], data[i]];
14395
+ }
13946
14396
  }
13947
14397
  return ce.function(xs.operator, data);
13948
14398
  }
@@ -14009,7 +14459,9 @@ var COLLECTIONS_LIBRARY = {
14009
14459
  if (t === "string")
14010
14460
  return parseType(`tuple<list<string>, list<integer>>`);
14011
14461
  return parseType(
14012
- `tuple<list<${collectionElementType(t)}>, list<integer>>`
14462
+ `tuple<list<${typeToString(
14463
+ collectionElementType(t) ?? "any"
14464
+ )}>, list<integer>>`
14013
14465
  );
14014
14466
  },
14015
14467
  evaluate: (ops, { engine: ce }) => {
@@ -14025,7 +14477,7 @@ var COLLECTIONS_LIBRARY = {
14025
14477
  description: "Return a list of the unique elements of the collection.",
14026
14478
  complexity: 8200,
14027
14479
  signature: "(collection) -> list",
14028
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
14480
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
14029
14481
  evaluate: (ops, { engine: ce }) => {
14030
14482
  if (!ops[0].isFiniteCollection) return void 0;
14031
14483
  const [values, _counts] = tally(ops[0]);
@@ -14037,7 +14489,7 @@ var COLLECTIONS_LIBRARY = {
14037
14489
  wikidata: "Q381060",
14038
14490
  complexity: 8200,
14039
14491
  signature: "(collection, integer | function) -> list",
14040
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
14492
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
14041
14493
  evaluate: ([xs, arg], { engine: ce }) => {
14042
14494
  if (!xs.isFiniteCollection) return void 0;
14043
14495
  const k = toInteger(arg);
@@ -14211,32 +14663,74 @@ var COLLECTIONS_LIBRARY = {
14211
14663
  }
14212
14664
  }
14213
14665
  },
14214
- // Repeat(x) -> [x, x, ...]
14215
- // This is an infinite series. Can use Take(Repeat(x), n) to get a finite series
14216
- // x is evaluated once. Although could use Hold()?
14217
- // So that First(Repeat(Hold(Random(5))), 10) would return 10 random numbers...
14666
+ // Repeat(x) -> [x, x, ...] — infinite sequence
14667
+ // Repeat(x, n) -> [x, x, ..., x] — finite list of n copies
14218
14668
  Repeat: {
14219
- description: "Produce an infinite sequence by repeating a single value.",
14669
+ description: "Produce a sequence by repeating a single value. With 1 argument, returns an infinite sequence; with 2 arguments (value, count), returns a finite list of `count` copies.",
14220
14670
  complexity: 8200,
14221
- signature: "(value: any) -> list",
14671
+ signature: "(value: any, count: integer?) -> list",
14672
+ evaluate: (ops, { engine }) => {
14673
+ if (ops.length !== 2) return void 0;
14674
+ const raw = toInteger(ops[1]);
14675
+ if (raw === null) return void 0;
14676
+ const n = Math.max(0, raw);
14677
+ if (n > engine.maxCollectionSize) return void 0;
14678
+ return engine._fn("List", Array(n).fill(ops[0]));
14679
+ },
14222
14680
  collection: {
14223
- isLazy: (_expr) => true,
14224
- count: () => Infinity,
14225
- isEmpty: (_expr) => false,
14226
- // Never empty
14227
- isFinite: () => false,
14228
- // Infinite collection
14681
+ isLazy: (expr) => isFunction2(expr) && expr.ops?.length === 1,
14682
+ count: (expr) => {
14683
+ if (!isFunction2(expr)) return void 0;
14684
+ if (expr.ops?.length === 2) {
14685
+ const n = toInteger(expr.op2);
14686
+ return n !== null ? Math.max(0, n) : void 0;
14687
+ }
14688
+ return Infinity;
14689
+ },
14690
+ isEmpty: (expr) => {
14691
+ if (!isFunction2(expr)) return void 0;
14692
+ if (expr.ops?.length === 2) {
14693
+ const n = toInteger(expr.op2);
14694
+ return n !== null ? n <= 0 : void 0;
14695
+ }
14696
+ return false;
14697
+ },
14698
+ isFinite: (expr) => isFunction2(expr) && expr.ops?.length === 2,
14229
14699
  contains: (expr, target) => {
14230
14700
  if (!isFunction2(expr)) return false;
14701
+ if (expr.ops?.length === 2) {
14702
+ const n = toInteger(expr.op2);
14703
+ if (n !== null && n <= 0) return false;
14704
+ }
14231
14705
  return expr.op1.isSame(target);
14232
14706
  },
14233
14707
  iterator: (expr) => {
14234
14708
  if (!isFunction2(expr))
14235
14709
  return { next: () => ({ value: void 0, done: true }) };
14710
+ if (expr.ops?.length === 2) {
14711
+ const n = toInteger(expr.op2);
14712
+ if (n === null) {
14713
+ return { next: () => ({ value: void 0, done: true }) };
14714
+ }
14715
+ const count = Math.max(0, n);
14716
+ let i = 0;
14717
+ return {
14718
+ next: () => i++ < count ? { value: expr.op1, done: false } : { value: void 0, done: true }
14719
+ };
14720
+ }
14236
14721
  return { next: () => ({ value: expr.op1, done: false }) };
14237
14722
  },
14238
- at: (expr, _index) => {
14723
+ // at is 1-based (consistent with Range, Take, and other collection handlers)
14724
+ at: (expr, index) => {
14239
14725
  if (!isFunction2(expr)) return void 0;
14726
+ if (typeof index !== "number") return void 0;
14727
+ if (expr.ops?.length === 2) {
14728
+ const n = toInteger(expr.op2);
14729
+ const count = n !== null ? Math.max(0, n) : 0;
14730
+ if (index < 1 || index > count) return void 0;
14731
+ } else {
14732
+ if (index < 1) return void 0;
14733
+ }
14240
14734
  return expr.op1;
14241
14735
  }
14242
14736
  }
@@ -14467,17 +14961,14 @@ function range(expr) {
14467
14961
  if (!isFunction2(expr)) return [1, 0, 0];
14468
14962
  if (expr.nops === 0) return [1, 0, 0];
14469
14963
  let op1 = expr.op1.re;
14470
- if (!isFinite(op1)) op1 = 1;
14471
- else op1 = Math.round(op1);
14964
+ if (!isFinite(op1) && !op1) op1 = 1;
14472
14965
  if (expr.nops === 1) return [1, op1, 1];
14473
14966
  let op2 = expr.op2.re;
14474
14967
  if (!isFinite(op2) && !op2) op2 = 1;
14475
- else if (isFinite(op2)) op2 = Math.round(op2);
14476
- if (expr.nops === 2) return [op1, op2, op2 > op1 ? 1 : -1];
14968
+ if (expr.nops === 2) return [op1, op2, op2 >= op1 ? 1 : -1];
14477
14969
  let op3 = expr.op3.re;
14478
- if (!isFinite(op3)) op3 = 1;
14479
- else op3 = Math.abs(Math.round(op3));
14480
- return [op1, op2, op1 < op2 ? op3 : -op3];
14970
+ if (!isFinite(op3) && !op3) op3 = 1;
14971
+ return [op1, op2, op3];
14481
14972
  }
14482
14973
  function canonicalList(ops, { engine: ce }) {
14483
14974
  const op1 = ops[0];
@@ -14826,6 +15317,23 @@ var BaseCompiler = class _BaseCompiler {
14826
15317
  };
14827
15318
  return compilePair(0);
14828
15319
  }
15320
+ if (h === "When") {
15321
+ if (args.length !== 2)
15322
+ throw new Error("When: expected exactly 2 arguments (expr, cond)");
15323
+ const fn2 = target.functions?.(h);
15324
+ if (fn2) {
15325
+ if (typeof fn2 === "function") {
15326
+ return fn2(args, (expr) => _BaseCompiler.compile(expr, target), target);
15327
+ }
15328
+ return `${fn2}(${args.map((x) => _BaseCompiler.compile(x, target)).join(", ")})`;
15329
+ }
15330
+ if (isSymbol2(args[1], "True"))
15331
+ return `(${_BaseCompiler.compile(args[0], target)})`;
15332
+ if (isSymbol2(args[1], "False")) return "NaN";
15333
+ const val = _BaseCompiler.compile(args[0], target);
15334
+ const cond = _BaseCompiler.compile(args[1], target);
15335
+ return `((${cond}) ? (${val}) : NaN)`;
15336
+ }
14829
15337
  if (h === "Block") {
14830
15338
  return _BaseCompiler.compileBlock(args, target);
14831
15339
  }
@@ -14900,17 +15408,98 @@ var BaseCompiler = class _BaseCompiler {
14900
15408
  )}${target.ws("\n")}})()`;
14901
15409
  }
14902
15410
  /**
14903
- * Compile a Loop expression with Element(index, Range(lo, hi)) indexing.
14904
- * Generates: (() => { for (let i = lo; i <= hi; i++) { body } })()
15411
+ * Compile a Loop expression.
14905
15412
  *
14906
- * The loop counter is always a raw number. For targets that wrap numeric
14907
- * values (e.g. interval-js wraps with `_IA.point()`), references to the
14908
- * loop index inside the body are wrapped via `target.number`.
15413
+ * Two forms are supported:
15414
+ *
15415
+ * 1. **Imperative / single-Element form** (existing behaviour):
15416
+ * `Loop(body, Element(i, Range(lo, hi)))`
15417
+ * Generates a raw `for (let i = lo; i <= hi; i++) { body }` loop wrapped
15418
+ * in an IIFE. The loop counter is always a plain number. For targets
15419
+ * that wrap numeric values (e.g. interval-js uses `_IA.point()`),
15420
+ * references to the loop index inside the body are re-wrapped via
15421
+ * `target.number`. `break` / `continue` / `return` are preserved.
15422
+ *
15423
+ * 2. **Comprehension / variadic-Element form** (new):
15424
+ * `Loop(body, Element(x, coll1), Element(y, coll2), …)`
15425
+ * When two or more `Element` clauses are present — or when the single
15426
+ * Element's collection is not a `Range` — the loop is compiled as a
15427
+ * comprehension that collects results into an array. Each clause
15428
+ * produces a `for (const name of collection)` loop, nested
15429
+ * outermost-to-innermost, and the innermost body pushes into `result`.
15430
+ *
15431
+ * Example output (JS):
15432
+ * ```js
15433
+ * (() => { const result = [];
15434
+ * for (const x of [1,2]) { for (const y of [3,4]) { result.push(body); } }
15435
+ * return result; })()
15436
+ * ```
15437
+ *
15438
+ * GLSL: multi-Element comprehension is not trivially representable in
15439
+ * GLSL (no dynamic arrays, no push). A compile-time error is thrown.
15440
+ * TODO(E3-GLSL): support GLSL multi-Element via a pre-declared fixed-size
15441
+ * array or by unrolling when bounds are known at compile time.
15442
+ *
15443
+ * Known issue (imperative form): the IIFE generated by form (1) has no
15444
+ * `return` statement, so `Loop(body, Element(i, Range(lo, hi)))` compiled
15445
+ * to JS evaluates to `undefined` at runtime, while CE evaluation returns a
15446
+ * `List` of body values. See `test/compute-engine/a1-c1-compile-parity.test.ts`
15447
+ * ("Loop compiles in JS") for the verify-only test that locks in the
15448
+ * current behavior.
14909
15449
  */
14910
15450
  static compileForLoop(args, target) {
14911
15451
  if (!args[0]) throw new Error("Loop: no body");
14912
15452
  if (!args[1]) throw new Error("Loop: no indexing set");
14913
- const indexing = args[1];
15453
+ const body = args[0];
15454
+ const elements = args.slice(1);
15455
+ const useComprehension = elements.length > 1 || elements.length === 1 && isFunction2(elements[0], "Element") && !_BaseCompiler.isLegacyCompatibleRange(elements[0].ops[1]);
15456
+ if (useComprehension) {
15457
+ const lang = target.language ?? "";
15458
+ if (lang === "glsl" || lang === "wgsl") {
15459
+ throw new Error(
15460
+ `${lang.toUpperCase()}: multi-Element Loop comprehension is not yet supported. TODO(E3-GLSL): unroll or use a fixed-size array.`
15461
+ );
15462
+ }
15463
+ const narrowedElements = [];
15464
+ for (let i = 0; i < elements.length; i++) {
15465
+ const elem = elements[i];
15466
+ if (!isFunction2(elem, "Element"))
15467
+ throw new Error(
15468
+ `Loop: argument ${i + 1} must be an Element clause, got ${elem.operator ?? "?"}`
15469
+ );
15470
+ if (!isSymbol2(elem.ops[0]))
15471
+ throw new Error(
15472
+ `Loop: Element index (argument ${i + 1}) must be a symbol`
15473
+ );
15474
+ narrowedElements.push(elem);
15475
+ }
15476
+ const loopVarSet = new Set(
15477
+ narrowedElements.map(
15478
+ (e) => e.ops[0].symbol
15479
+ )
15480
+ );
15481
+ const needsWrap2 = target.number(0) !== "0";
15482
+ const bodyTarget2 = needsWrap2 ? {
15483
+ ...target,
15484
+ var: (id) => loopVarSet.has(id) ? target.number(0).replace("0", id) : target.var(id)
15485
+ } : target;
15486
+ const bodyCode = _BaseCompiler.compile(body, bodyTarget2);
15487
+ let inner = `result.push(${bodyCode});`;
15488
+ for (let i = narrowedElements.length - 1; i >= 0; i--) {
15489
+ const elem = narrowedElements[i];
15490
+ const name = elem.ops[0].symbol;
15491
+ const collExpr = elem.ops[1];
15492
+ let collection;
15493
+ if (isFunction2(collExpr, "Range")) {
15494
+ collection = _BaseCompiler.compileRangeIterable(collExpr, bodyTarget2);
15495
+ } else {
15496
+ collection = _BaseCompiler.compile(collExpr, bodyTarget2);
15497
+ }
15498
+ inner = `for (const ${name} of ${collection}) { ${inner} }`;
15499
+ }
15500
+ return `(() => { const result = []; ${inner} return result; })()`;
15501
+ }
15502
+ const indexing = elements[0];
14914
15503
  if (!isFunction2(indexing, "Element"))
14915
15504
  throw new Error("Loop: expected Element(index, Range(lo, hi))");
14916
15505
  const indexExpr = indexing.ops[0];
@@ -14928,13 +15517,72 @@ var BaseCompiler = class _BaseCompiler {
14928
15517
  ...target,
14929
15518
  var: (id) => id === index ? needsWrap ? target.number(0).replace("0", index) : index : target.var(id)
14930
15519
  };
14931
- const bodyStmts = _BaseCompiler.compileLoopBody(args[0], bodyTarget);
15520
+ const bodyStmts = _BaseCompiler.compileLoopBody(body, bodyTarget);
14932
15521
  return `(() => {${target.ws(
14933
15522
  "\n"
14934
15523
  )}for (let ${index} = ${lower}; ${index} <= ${upper}; ${index}++) {${target.ws(
14935
15524
  "\n"
14936
15525
  )}${bodyStmts}${target.ws("\n")}}${target.ws("\n")}})()`;
14937
15526
  }
15527
+ /**
15528
+ * Returns `true` when the given collection expression is a `Range` whose
15529
+ * runtime semantics match the legacy imperative for-loop shape
15530
+ * `for (let i = lo; i <= hi; i++)`.
15531
+ *
15532
+ * Concretely: integer-ascending bounds and step omitted-or-1. When bounds
15533
+ * are not statically numeric we accept the Range (the historical
15534
+ * behaviour) — runtime mismatch in the descending-unknown-bounds case is
15535
+ * left as a known limitation; callers can force the iterable path by
15536
+ * supplying an explicit step.
15537
+ */
15538
+ static isLegacyCompatibleRange(coll) {
15539
+ if (!isFunction2(coll, "Range")) return false;
15540
+ if (coll.ops.length >= 3) {
15541
+ const stepExpr = coll.ops[2];
15542
+ if (!isNumber(stepExpr) || stepExpr.re !== 1) return false;
15543
+ }
15544
+ const lo = coll.ops[0];
15545
+ const hi = coll.ops[1];
15546
+ if (isNumber(lo) && !Number.isInteger(lo.re)) return false;
15547
+ if (isNumber(hi) && !Number.isInteger(hi.re)) return false;
15548
+ if (isNumber(lo) && isNumber(hi) && lo.re > hi.re) return false;
15549
+ return true;
15550
+ }
15551
+ /**
15552
+ * Compile a `Range(lo, hi)` or `Range(lo, hi, step)` expression into a JS
15553
+ * iterable expression. Mirrors the runtime semantics in
15554
+ * `library/collections.ts` Range:
15555
+ * count = step === 0 ? 0 : max(0, floor((hi - lo) / step) + 1)
15556
+ * element = lo + step * k (0-indexed)
15557
+ * Default step is 1 when omitted. Bounds and step may be fractional.
15558
+ *
15559
+ * Only used from the comprehension path in `compileForLoop`.
15560
+ * Caller must have already verified `isFunction(rangeExpr, 'Range')`.
15561
+ */
15562
+ static compileRangeIterable(rangeExpr, target) {
15563
+ const loExpr = rangeExpr.ops[0];
15564
+ const hiExpr = rangeExpr.ops[1];
15565
+ const stepExpr = rangeExpr.ops[2];
15566
+ if (isNumber(loExpr) && isNumber(hiExpr) && (stepExpr === void 0 || isNumber(stepExpr))) {
15567
+ const lo2 = loExpr.re;
15568
+ const hi2 = hiExpr.re;
15569
+ const step2 = stepExpr === void 0 ? hi2 >= lo2 ? 1 : -1 : stepExpr.re;
15570
+ if (step2 === 0) return "[]";
15571
+ const len = Math.max(0, Math.floor((hi2 - lo2) / step2) + 1);
15572
+ if (step2 === 1) {
15573
+ if (lo2 === 0) return `Array.from({length:${len}},(_,k)=>k)`;
15574
+ return `Array.from({length:${len}},(_,k)=>${lo2}+k)`;
15575
+ }
15576
+ return `Array.from({length:${len}},(_,k)=>${lo2}+(${step2})*k)`;
15577
+ }
15578
+ const lo = _BaseCompiler.compile(loExpr, target);
15579
+ const hi = _BaseCompiler.compile(hiExpr, target);
15580
+ if (stepExpr === void 0) {
15581
+ return `((_lo,_hi)=>{const _st=_hi>=_lo?1:-1;return Array.from({length:Math.max(0,Math.floor((_hi-_lo)/_st)+1)},(_,k)=>_lo+_st*k);})(${lo},${hi})`;
15582
+ }
15583
+ const step = _BaseCompiler.compile(stepExpr, target);
15584
+ return `((_lo,_hi,_st)=>_st===0?[]:Array.from({length:Math.max(0,Math.floor((_hi-_lo)/_st)+1)},(_,k)=>_lo+_st*k))(${lo},${hi},${step})`;
15585
+ }
14938
15586
  /**
14939
15587
  * Compile a loop body expression as statements (not wrapped in IIFE).
14940
15588
  * Handles Break, Continue, Return as statements, and If as if-else when
@@ -19885,6 +20533,7 @@ var JAVASCRIPT_FUNCTIONS = {
19885
20533
  return `_SYS.cexp(${compile2(args[0])})`;
19886
20534
  return `Math.exp(${compile2(args[0])})`;
19887
20535
  },
20536
+ First: (args, compile2) => `${compile2(args[0])}[0]`,
19888
20537
  Floor: (args, compile2) => {
19889
20538
  if (BaseCompiler.isIntegerValued(args[0])) return compile2(args[0]);
19890
20539
  return `Math.floor(${compile2(args[0])})`;
@@ -20043,7 +20692,20 @@ var JAVASCRIPT_FUNCTIONS = {
20043
20692
  if (nConst !== void 0) return `Math.pow(${compile2(arg)}, ${1 / nConst})`;
20044
20693
  return `Math.pow(${compile2(arg)}, 1 / (${compile2(exp3)}))`;
20045
20694
  },
20046
- Random: "Math.random",
20695
+ Random: (args, compile2) => {
20696
+ if (args.length === 0) return "Math.random()";
20697
+ if (args.length === 2) {
20698
+ const m = compile2(args[0]);
20699
+ const n = compile2(args[1]);
20700
+ return `((${m}) + Math.floor(Math.random() * ((${n}) - (${m}))))`;
20701
+ }
20702
+ const arg = args[0];
20703
+ if (BaseCompiler.isIntegerValued(arg)) {
20704
+ return `Math.floor(Math.random() * (${compile2(arg)}))`;
20705
+ }
20706
+ const a = compile2(arg);
20707
+ return `(() => { const _s = (${a}) * 12.9898; const _v = Math.sin(_s) * 43758.5453; return _v - Math.floor(_v); })()`;
20708
+ },
20047
20709
  Round: (args, compile2) => {
20048
20710
  if (BaseCompiler.isIntegerValued(args[0])) return compile2(args[0]);
20049
20711
  return `Math.round(${compile2(args[0])})`;
@@ -20071,6 +20733,7 @@ var JAVASCRIPT_FUNCTIONS = {
20071
20733
  if (BaseCompiler.isComplexValued(arg)) return `_SYS.csech(${compile2(arg)})`;
20072
20734
  return `1 / Math.cosh(${compile2(arg)})`;
20073
20735
  },
20736
+ Second: (args, compile2) => `${compile2(args[0])}[1]`,
20074
20737
  Heaviside: "_SYS.heaviside",
20075
20738
  Sign: "Math.sign",
20076
20739
  Sinc: "_SYS.sinc",
@@ -20103,6 +20766,7 @@ var JAVASCRIPT_FUNCTIONS = {
20103
20766
  return `_SYS.ctanh(${compile2(args[0])})`;
20104
20767
  return `Math.tanh(${compile2(args[0])})`;
20105
20768
  },
20769
+ Third: (args, compile2) => `${compile2(args[0])}[2]`,
20106
20770
  Mod: ([a, b], compile2) => {
20107
20771
  if (a === null || b === null) throw new Error("Mod: missing argument");
20108
20772
  const ca = compile2(a);
@@ -21382,6 +22046,14 @@ var GPU_FUNCTIONS = {
21382
22046
  return `exp(${compile2(args[0])})`;
21383
22047
  },
21384
22048
  Exp2: "exp2",
22049
+ // Component access — assumes the argument compiles to a vec2/vec3/vec4
22050
+ // (the common case for 2D/3D points). For 5+-element tuples that compile
22051
+ // to `float[N]` arrays, swizzle access is invalid GLSL and the shader
22052
+ // will fail to compile; that's an edge case `First`/`Second`/`Third`
22053
+ // aren't designed for. Vec swizzles are identical between GLSL and WGSL.
22054
+ First: (args, compile2) => `${compile2(args[0])}.x`,
22055
+ Second: (args, compile2) => `${compile2(args[0])}.y`,
22056
+ Third: (args, compile2) => `${compile2(args[0])}.z`,
21385
22057
  Floor: (args, compile2) => {
21386
22058
  if (BaseCompiler.isIntegerValued(args[0])) return compile2(args[0]);
21387
22059
  return `floor(${compile2(args[0])})`;
@@ -21859,6 +22531,39 @@ var GPU_FUNCTIONS = {
21859
22531
  // Sum/Product — unrolled or for-loop
21860
22532
  Sum: (args, compile2, target) => compileGPUSumProduct("Sum", args, compile2, target),
21861
22533
  Product: (args, compile2, target) => compileGPUSumProduct("Product", args, compile2, target),
22534
+ // Range — inline constant array literal (bounds must be compile-time constants)
22535
+ Range: (args, _compile, target) => {
22536
+ if (args.length < 2 || args.length > 3) {
22537
+ throw new Error(
22538
+ "Range: GPU compile expects 2 or 3 arguments (lo, hi, step?)"
22539
+ );
22540
+ }
22541
+ const lo = args[0].re;
22542
+ const hi = args[1].re;
22543
+ const step = args.length === 3 ? args[2].re : 1;
22544
+ if (!Number.isFinite(lo) || !Number.isFinite(hi) || !Number.isFinite(step)) {
22545
+ throw new Error(
22546
+ "Range: GPU compile requires constant numeric bounds (non-constant ranges must be materialized at JS host then uploaded as a uniform)"
22547
+ );
22548
+ }
22549
+ if (step === 0) throw new Error("Range: step cannot be zero");
22550
+ const count = Math.max(0, Math.floor((hi - lo) / step) + 1);
22551
+ if (count === 0) {
22552
+ throw new Error(
22553
+ "Range: empty range (lo > hi for positive step, or lo < hi for negative step)"
22554
+ );
22555
+ }
22556
+ if (count > 256) {
22557
+ throw new Error(
22558
+ `Range: GPU compile inlines ranges up to 256 elements (got ${count})`
22559
+ );
22560
+ }
22561
+ const values = [];
22562
+ for (let i = 0; i < count; i++) values.push(lo + i * step);
22563
+ const isWGSL = target.language === "wgsl";
22564
+ const arrayType = isWGSL ? `array<f32, ${count}>` : `float[${count}]`;
22565
+ return `${arrayType}(${values.map(formatGPUNumber).join(", ")})`;
22566
+ },
21862
22567
  // Loop — GPU for-loop (no IIFE, no let)
21863
22568
  Loop: (args, _compile, target) => {
21864
22569
  if (!args[0]) throw new Error("Loop: no body");
@@ -21887,6 +22592,134 @@ var GPU_FUNCTIONS = {
21887
22592
  ${bodyCode};
21888
22593
  }`;
21889
22594
  },
22595
+ // Statistical functions
22596
+ /**
22597
+ * GCD of two scalar arguments.
22598
+ *
22599
+ * Uses a preamble helper `_gpu_gcd` (Euclidean algorithm via `mod`).
22600
+ * Only two-argument form is supported in GPU targets.
22601
+ */
22602
+ GCD: (args, compile2) => {
22603
+ if (args.length < 2) throw new Error("GCD: need at least two arguments");
22604
+ if (args.length > 2)
22605
+ throw new Error("GCD: GPU target supports only two-argument GCD");
22606
+ const a = args[0];
22607
+ const b = args[1];
22608
+ if (a === null || b === null) throw new Error("GCD: missing argument");
22609
+ return `_gpu_gcd(${compile2(a)}, ${compile2(b)})`;
22610
+ },
22611
+ /**
22612
+ * Variance of a compile-time-known list.
22613
+ *
22614
+ * Accepts either a single `List(...)` argument or N scalar arguments.
22615
+ * Generates fully inline code: computes mean then sum of squared deviations,
22616
+ * divided by (N-1) for sample variance (matches JS `_SYS.variance`).
22617
+ */
22618
+ Variance: (args, compile2) => {
22619
+ let elems;
22620
+ if (args.length === 1 && isFunction2(args[0], "List")) {
22621
+ elems = args[0].ops;
22622
+ } else if (args.length >= 2) {
22623
+ elems = args;
22624
+ } else {
22625
+ throw new Error(
22626
+ "Variance: GPU target requires a List argument or at least 2 scalar arguments"
22627
+ );
22628
+ }
22629
+ const n = elems.length;
22630
+ if (n < 2) throw new Error("Variance: need at least 2 elements");
22631
+ const compiled = elems.map((e) => compile2(e));
22632
+ const sum = compiled.join(" + ");
22633
+ const mean2 = `((${sum}) / ${formatGPUNumber(n)})`;
22634
+ const sqDiffs = compiled.map((c) => `(${c} - ${mean2}) * (${c} - ${mean2})`).join(" + ");
22635
+ return `((${sqDiffs}) / ${formatGPUNumber(n - 1)})`;
22636
+ },
22637
+ /**
22638
+ * Median of a compile-time-known list.
22639
+ *
22640
+ * Accepts either a single `List(...)` argument or N scalar arguments.
22641
+ * For N ≤ 8: generates a fully unrolled inline sorting network followed by
22642
+ * a middle-element pick. For larger N, throws (too large to inline cleanly).
22643
+ *
22644
+ * The sorting network uses the "odd-even merge sort" comparator pattern
22645
+ * inlined as `min`/`max` calls — no GPU statements required.
22646
+ */
22647
+ Median: (args, compile2) => {
22648
+ let elems;
22649
+ if (args.length === 1 && isFunction2(args[0], "List")) {
22650
+ elems = args[0].ops;
22651
+ } else if (args.length >= 1) {
22652
+ elems = args;
22653
+ } else {
22654
+ throw new Error(
22655
+ "Median: GPU target requires a List argument or at least 1 scalar argument"
22656
+ );
22657
+ }
22658
+ const n = elems.length;
22659
+ if (n === 0) throw new Error("Median: empty list");
22660
+ if (n > 8) {
22661
+ throw new Error(
22662
+ `Median: GPU target supports up to 8 elements via inline sorting network (got ${n}). For larger lists, compute on the CPU and pass the result as a uniform.`
22663
+ );
22664
+ }
22665
+ const compiled = elems.map((e) => compile2(e));
22666
+ if (n === 1) return compiled[0];
22667
+ return `_gpu_median_${n}(${compiled.join(", ")})`;
22668
+ },
22669
+ /**
22670
+ * Deterministic pseudorandom for GPU.
22671
+ *
22672
+ * All emitted forms return a GLSL `float` (or WGSL `f32`) so the result
22673
+ * composes with surrounding float arithmetic without explicit casts. The
22674
+ * "integer-bound" forms return an integer-valued float (the result of
22675
+ * `floor`), matching the convention used by `Floor` and other ostensibly
22676
+ * integer-returning operators in this target.
22677
+ *
22678
+ * - 0 args (GLSL only): fall back to a fragment-coord-derived seed.
22679
+ * Only meaningful in fragment shaders (gl_FragCoord is FS-only).
22680
+ * - 0 args (WGSL): throws — WGSL has no built-in fragment coordinate;
22681
+ * caller must provide an explicit seed.
22682
+ * - 1 arg, real-typed: `_gpu_random(seed)` — deterministic float in [0, 1)
22683
+ * - 1 arg, integer-typed: `floor(_gpu_random(float(n)) * float(n))` —
22684
+ * integer-valued float in {0, 1, ..., n-1}. The seed is derived from
22685
+ * `n` itself, so the result is per-pixel-and-n deterministic in GLSL.
22686
+ * - 2 args (integer m, n): float in [m, n), seeded from gl_FragCoord.
22687
+ *
22688
+ * JS-side `Random` has matching semantics (see `library/core.ts`'s
22689
+ * polymorphic dispatch). JS↔GLSL parity is approximate — same seed yields
22690
+ * a similar value, not bit-identical, due to fp64 vs fp32 and platform
22691
+ * `sin` differences.
22692
+ */
22693
+ Random: (args, compile2, target) => {
22694
+ if (args.length === 0) {
22695
+ if (target.language === "wgsl") {
22696
+ throw new Error(
22697
+ "Random(): WGSL compile requires an explicit seed argument. WGSL has no gl_FragCoord built-in outside fragment entry points, so the no-arg fallback used in GLSL is unavailable. Use Random(seed) where seed is a deterministic per-invocation value."
22698
+ );
22699
+ }
22700
+ return "_gpu_random(gl_FragCoord.x + gl_FragCoord.y * 1024.0)";
22701
+ }
22702
+ if (args.length === 1) {
22703
+ const arg = args[0];
22704
+ if (BaseCompiler.isIntegerValued(arg)) {
22705
+ const compiled = compile2(arg);
22706
+ return `floor(_gpu_random(float(${compiled})) * float(${compiled}))`;
22707
+ }
22708
+ return `_gpu_random(${compile2(arg)})`;
22709
+ }
22710
+ if (args.length === 2) {
22711
+ if (target.language === "wgsl") {
22712
+ throw new Error(
22713
+ "Random(m, n): WGSL compile requires explicit seeding. Use a seeded variant or compute the integer range manually."
22714
+ );
22715
+ }
22716
+ const m = compile2(args[0]);
22717
+ const n = compile2(args[1]);
22718
+ const seed = "_gpu_random(gl_FragCoord.x + gl_FragCoord.y * 1024.0)";
22719
+ return `(float(${m}) + floor(${seed} * float((${n}) - (${m}))))`;
22720
+ }
22721
+ throw new Error("Random: GPU compile expects 0, 1, or 2 arguments");
22722
+ },
21890
22723
  // Function (lambda) — not supported in GPU
21891
22724
  Function: () => {
21892
22725
  throw new Error(
@@ -22486,6 +23319,212 @@ fn _fractal_julia(z_in: vec2f, c: vec2f, maxIter: i32) -> f32 {
22486
23319
  return 1.0;
22487
23320
  }
22488
23321
  `;
23322
+ var GPU_GCD_PREAMBLE_GLSL = `
23323
+ float _gpu_gcd(float a, float b) {
23324
+ a = abs(a); b = abs(b);
23325
+ for (int i = 0; i < 32; i++) {
23326
+ if (b < 0.5) break;
23327
+ float t = mod(a, b);
23328
+ a = b;
23329
+ b = t;
23330
+ }
23331
+ return a;
23332
+ }
23333
+ `;
23334
+ var GPU_GCD_PREAMBLE_WGSL = `
23335
+ fn _gpu_gcd(a_in: f32, b_in: f32) -> f32 {
23336
+ var a = abs(a_in); var b = abs(b_in);
23337
+ for (var i: i32 = 0; i < 32; i++) {
23338
+ if (b < 0.5) { break; }
23339
+ let t = a % b;
23340
+ a = b;
23341
+ b = t;
23342
+ }
23343
+ return a;
23344
+ }
23345
+ `;
23346
+ var GPU_RANDOM_PREAMBLE_GLSL = `
23347
+ // Deterministic pseudorandom in [0, 1) from a float seed.
23348
+ // Standard fract-sin hash; reproducible across runs for the same seed.
23349
+ // Note: this hash exhibits visible banding near seed \u2248 k\u03C0 for integer k.
23350
+ // For high-quality shader random, callers should use a more robust hash
23351
+ // (e.g. PCG or xxHash) and pre-seed it appropriately.
23352
+ float _gpu_random(float seed) {
23353
+ return fract(sin(seed * 12.9898) * 43758.5453);
23354
+ }
23355
+ `;
23356
+ var GPU_RANDOM_PREAMBLE_WGSL = `
23357
+ // Deterministic pseudorandom in [0, 1) from a float seed.
23358
+ // Standard fract-sin hash; reproducible across runs for the same seed.
23359
+ // Note: this hash exhibits visible banding near seed \u2248 k\u03C0 for integer k.
23360
+ // For high-quality shader random, callers should use a more robust hash
23361
+ // (e.g. PCG or xxHash) and pre-seed it appropriately.
23362
+ fn _gpu_random(seed: f32) -> f32 {
23363
+ return fract(sin(seed * 12.9898) * 43758.5453);
23364
+ }
23365
+ `;
23366
+ var GPU_MEDIAN_PREAMBLE_GLSL = `
23367
+ float _gpu_median_2(float a, float b) {
23368
+ return (a + b) * 0.5;
23369
+ }
23370
+ float _gpu_median_3(float a, float b, float c) {
23371
+ return max(min(a, b), min(max(a, b), c));
23372
+ }
23373
+ float _gpu_median_4(float a, float b, float c, float d) {
23374
+ float lo = max(min(a, b), min(c, d));
23375
+ float hi = min(max(a, b), max(c, d));
23376
+ return (lo + hi) * 0.5;
23377
+ }
23378
+ float _gpu_median_5(float a, float b, float c, float d, float e) {
23379
+ // 9-comparator Bose-Nelson sort; v2 holds the median.
23380
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e;
23381
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
23382
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23383
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
23384
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
23385
+ t=min(v0,v3); v3=max(v0,v3); v0=t;
23386
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
23387
+ t=min(v1,v4); v4=max(v1,v4); v1=t;
23388
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
23389
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
23390
+ return v2;
23391
+ }
23392
+ float _gpu_median_6(float a, float b, float c, float d, float e, float f) {
23393
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f;
23394
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
23395
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
23396
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
23397
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
23398
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
23399
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
23400
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
23401
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
23402
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
23403
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
23404
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23405
+ return (v2 + v3) * 0.5;
23406
+ }
23407
+ float _gpu_median_7(float a, float b, float c, float d, float e, float f, float g) {
23408
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f,v6=g;
23409
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
23410
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
23411
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
23412
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
23413
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
23414
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
23415
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
23416
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
23417
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
23418
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
23419
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
23420
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
23421
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23422
+ return v3;
23423
+ }
23424
+ float _gpu_median_8(float a, float b, float c, float d, float e, float f, float g, float h) {
23425
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f,v6=g,v7=h;
23426
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
23427
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
23428
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
23429
+ t=min(v6,v7); v7=max(v6,v7); v6=t;
23430
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
23431
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
23432
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
23433
+ t=min(v5,v7); v7=max(v5,v7); v5=t;
23434
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
23435
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
23436
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
23437
+ t=min(v3,v7); v7=max(v3,v7); v3=t;
23438
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
23439
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23440
+ t=min(v5,v6); v6=max(v5,v6); v5=t;
23441
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
23442
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
23443
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23444
+ return (v3 + v4) * 0.5;
23445
+ }
23446
+ `;
23447
+ var GPU_MEDIAN_PREAMBLE_WGSL = `
23448
+ fn _gpu_median_2(a: f32, b: f32) -> f32 {
23449
+ return (a + b) * 0.5;
23450
+ }
23451
+ fn _gpu_median_3(a: f32, b: f32, c: f32) -> f32 {
23452
+ return max(min(a, b), min(max(a, b), c));
23453
+ }
23454
+ fn _gpu_median_4(a: f32, b: f32, c: f32, d: f32) -> f32 {
23455
+ let lo = max(min(a, b), min(c, d));
23456
+ let hi = min(max(a, b), max(c, d));
23457
+ return (lo + hi) * 0.5;
23458
+ }
23459
+ fn _gpu_median_5(a: f32, b: f32, c: f32, d: f32, e: f32) -> f32 {
23460
+ // 9-comparator Bose-Nelson sort; v2 holds the median.
23461
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var t: f32;
23462
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
23463
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23464
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
23465
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
23466
+ t=min(v0,v3); v3=max(v0,v3); v0=t;
23467
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
23468
+ t=min(v1,v4); v4=max(v1,v4); v1=t;
23469
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
23470
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
23471
+ return v2;
23472
+ }
23473
+ fn _gpu_median_6(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) -> f32 {
23474
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var v5=f; var t: f32;
23475
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
23476
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
23477
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
23478
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
23479
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
23480
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
23481
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
23482
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
23483
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
23484
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
23485
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23486
+ return (v2 + v3) * 0.5;
23487
+ }
23488
+ fn _gpu_median_7(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32, g: f32) -> f32 {
23489
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var v5=f; var v6=g; var t: f32;
23490
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
23491
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
23492
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
23493
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
23494
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
23495
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
23496
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
23497
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
23498
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
23499
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
23500
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
23501
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
23502
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23503
+ return v3;
23504
+ }
23505
+ fn _gpu_median_8(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32, g: f32, h: f32) -> f32 {
23506
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var v5=f; var v6=g; var v7=h; var t: f32;
23507
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
23508
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
23509
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
23510
+ t=min(v6,v7); v7=max(v6,v7); v6=t;
23511
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
23512
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
23513
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
23514
+ t=min(v5,v7); v7=max(v5,v7); v5=t;
23515
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
23516
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
23517
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
23518
+ t=min(v3,v7); v7=max(v3,v7); v3=t;
23519
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
23520
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23521
+ t=min(v5,v6); v6=max(v5,v6); v5=t;
23522
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
23523
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
23524
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23525
+ return (v3 + v4) * 0.5;
23526
+ }
23527
+ `;
22489
23528
  var GPU_COLOR_PREAMBLE_GLSL = `
22490
23529
  float _gpu_srgb_to_linear(float c) {
22491
23530
  if (c <= 0.04045) return c / 12.92;
@@ -23163,6 +24202,12 @@ var GPUShaderTarget = class {
23163
24202
  if (code.includes("_fractal_")) {
23164
24203
  preamble += this.languageId === "wgsl" ? GPU_FRACTAL_PREAMBLE_WGSL : GPU_FRACTAL_PREAMBLE_GLSL;
23165
24204
  }
24205
+ if (code.includes("_gpu_random"))
24206
+ preamble += this.languageId === "wgsl" ? GPU_RANDOM_PREAMBLE_WGSL : GPU_RANDOM_PREAMBLE_GLSL;
24207
+ if (code.includes("_gpu_gcd"))
24208
+ preamble += this.languageId === "wgsl" ? GPU_GCD_PREAMBLE_WGSL : GPU_GCD_PREAMBLE_GLSL;
24209
+ if (code.includes("_gpu_median_"))
24210
+ preamble += this.languageId === "wgsl" ? GPU_MEDIAN_PREAMBLE_WGSL : GPU_MEDIAN_PREAMBLE_GLSL;
23166
24211
  if (code.includes("_gpu_srgb_to") || code.includes("_gpu_oklab") || code.includes("_gpu_oklch") || code.includes("_gpu_color_mix") || code.includes("_gpu_apca")) {
23167
24212
  preamble += this.languageId === "wgsl" ? GPU_COLOR_PREAMBLE_WGSL : GPU_COLOR_PREAMBLE_GLSL;
23168
24213
  }
@@ -25501,7 +26546,7 @@ function compileToIntervalTarget(expr, target) {
25501
26546
  }
25502
26547
 
25503
26548
  // src/compile.ts
25504
- var version = "0.56.0";
26549
+ var version = "0.58.0";
25505
26550
  export {
25506
26551
  BaseCompiler,
25507
26552
  GLSLTarget,