@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
- /** Compile 0.56.0 */
1
+ /** Compile 0.58.0 */
2
2
  (function(global,factory){typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'],factory):(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Compile = {}));})(this, (function (exports) { 'use strict';
3
3
  var Compile = (() => {
4
4
  var __defProp = Object.defineProperty;
@@ -3568,7 +3568,42 @@ var Compile = (() => {
3568
3568
  if (b === "nothing") return a;
3569
3569
  if (isSubtype(a, b)) return b;
3570
3570
  if (isSubtype(b, a)) return a;
3571
- return superType(a, b);
3571
+ const sup = superType(a, b);
3572
+ if (LOSSY_SUPERTYPE.has(sup)) return unionTypes(a, b);
3573
+ return sup;
3574
+ }
3575
+ var LOSSY_SUPERTYPE = /* @__PURE__ */ new Set([
3576
+ "scalar",
3577
+ "value",
3578
+ "function",
3579
+ "expression",
3580
+ "collection",
3581
+ "indexed_collection",
3582
+ "list",
3583
+ "set",
3584
+ "tuple",
3585
+ "record",
3586
+ "dictionary",
3587
+ "map",
3588
+ "any"
3589
+ ]);
3590
+ function unionTypes(a, b) {
3591
+ const members = [];
3592
+ const push = (t) => {
3593
+ if (typeof t === "object" && t.kind === "union") {
3594
+ for (const m of t.types) push(m);
3595
+ return;
3596
+ }
3597
+ const key = typeof t === "string" ? t : JSON.stringify(t);
3598
+ if (!members.some(
3599
+ (m) => (typeof m === "string" ? m : JSON.stringify(m)) === key
3600
+ ))
3601
+ members.push(t);
3602
+ };
3603
+ push(a);
3604
+ push(b);
3605
+ if (members.length === 1) return members[0];
3606
+ return { kind: "union", types: members };
3572
3607
  }
3573
3608
  function narrow(...types) {
3574
3609
  if (types.length === 0) return "nothing";
@@ -3642,7 +3677,7 @@ var Compile = (() => {
3642
3677
  if (type.kind === "set") return type.elements;
3643
3678
  if (type.kind === "tuple") return widen(...type.elements.map((x) => x.type));
3644
3679
  if (type.kind === "dictionary")
3645
- return parseType(`tuple<string, ${type.values}>`);
3680
+ return parseType(`tuple<string, ${typeToString(type.values)}>`);
3646
3681
  if (type.kind === "record") {
3647
3682
  return parseType(
3648
3683
  `tuple<string, ${typeToString(widen(...Object.values(type.elements)))}>`
@@ -5211,6 +5246,64 @@ var Compile = (() => {
5211
5246
  }
5212
5247
 
5213
5248
  // src/compute-engine/latex-syntax/dictionary/definitions-core.ts
5249
+ var COMPONENT_ACCESS_HEADS = {
5250
+ x: "First",
5251
+ y: "Second",
5252
+ z: "Third",
5253
+ real: "Real",
5254
+ re: "Real",
5255
+ imag: "Imaginary",
5256
+ im: "Imaginary",
5257
+ count: "Length",
5258
+ total: "Sum",
5259
+ max: "Max",
5260
+ min: "Min"
5261
+ };
5262
+ function memberHead(name) {
5263
+ return COMPONENT_ACCESS_HEADS[name] ?? null;
5264
+ }
5265
+ function parseComponentAccess(parser, lhs) {
5266
+ parser.skipVisualSpace();
5267
+ if (parser.match("\\operatorname")) {
5268
+ const name = parser.parseStringGroup();
5269
+ if (name === null) return null;
5270
+ const head = memberHead(name.trim());
5271
+ if (head === null) return null;
5272
+ return [head, lhs];
5273
+ }
5274
+ const tok = parser.peek;
5275
+ if (typeof tok === "string" && tok.startsWith("\\")) {
5276
+ const bare = tok.slice(1);
5277
+ const head = memberHead(bare);
5278
+ if (head !== null) {
5279
+ parser.nextToken();
5280
+ return [head, lhs];
5281
+ }
5282
+ return null;
5283
+ }
5284
+ if (typeof tok === "string" && /^[a-zA-Z]$/.test(tok)) {
5285
+ const head = memberHead(tok);
5286
+ if (head === null) return null;
5287
+ parser.nextToken();
5288
+ return [head, lhs];
5289
+ }
5290
+ return null;
5291
+ }
5292
+ function parseWhenRestriction(parser, lhs, close) {
5293
+ parser.addBoundary(close);
5294
+ parser.skipVisualSpace();
5295
+ const cond = parser.parseExpression({ minPrec: 0 });
5296
+ if (cond === null) {
5297
+ parser.removeBoundary();
5298
+ return null;
5299
+ }
5300
+ parser.skipVisualSpace();
5301
+ if (!parser.matchBoundary()) {
5302
+ parser.removeBoundary();
5303
+ return null;
5304
+ }
5305
+ return ["When", lhs, cond];
5306
+ }
5214
5307
  function parseSequence(parser, terminator, lhs, prec, sep) {
5215
5308
  if (terminator && terminator.minPrec >= prec) return null;
5216
5309
  const result = lhs ? [lhs] : ["Nothing"];
@@ -5486,15 +5579,16 @@ var Compile = (() => {
5486
5579
  precedence: ASSIGNMENT_PRECEDENCE,
5487
5580
  parse: parseAssign
5488
5581
  },
5489
- // General colon operator (type annotation, mapping notation)
5490
- // Precedence below assignment (260) so `:=` takes priority,
5491
- // and below arrows (270) so `f: A \to B` parses as `Colon(f, To(A, B))`
5582
+ // General colon operator (type annotation, mapping notation, Desmos piecewise)
5583
+ // Precedence below comparisons (245) so `cond : val` (Desmos compact piecewise)
5584
+ // parses as `Colon(cond, val)`, and below arrows (270) so
5585
+ // `f: A \to B` parses as `Colon(f, To(A, B))`.
5492
5586
  {
5493
5587
  name: "Colon",
5494
5588
  latexTrigger: ":",
5495
5589
  kind: "infix",
5496
5590
  associativity: "right",
5497
- precedence: 250,
5591
+ precedence: 240,
5498
5592
  serialize: (serializer, expr) => joinLatex([
5499
5593
  serializer.serialize(operand(expr, 1)),
5500
5594
  "\\colon",
@@ -5505,7 +5599,7 @@ var Compile = (() => {
5505
5599
  latexTrigger: "\\colon",
5506
5600
  kind: "infix",
5507
5601
  associativity: "right",
5508
- precedence: 250,
5602
+ precedence: 240,
5509
5603
  parse: "Colon"
5510
5604
  },
5511
5605
  {
@@ -5682,6 +5776,15 @@ var Compile = (() => {
5682
5776
  }
5683
5777
  },
5684
5778
  { name: "LatexTokens", serialize: serializeLatexTokens },
5779
+ // Component-access postfix: expr.member (C3)
5780
+ // The '.' trigger is consumed before the parse function is called.
5781
+ // Precedence 850 > 810 (At/indexing) so .x chains tightly.
5782
+ {
5783
+ kind: "postfix",
5784
+ precedence: 850,
5785
+ latexTrigger: ["."],
5786
+ parse: parseComponentAccess
5787
+ },
5685
5788
  {
5686
5789
  name: "At",
5687
5790
  kind: "postfix",
@@ -5702,6 +5805,29 @@ var Compile = (() => {
5702
5805
  latexTrigger: ["\\left", "\\lbrack"],
5703
5806
  parse: parseAt("\\right", "\\rbrack")
5704
5807
  },
5808
+ // When-restriction: `expr\left\{cond\right\}` → `When(expr, cond)` (D3)
5809
+ {
5810
+ name: "When",
5811
+ kind: "postfix",
5812
+ precedence: 800,
5813
+ latexTrigger: ["\\left", "\\{"],
5814
+ parse: (parser, lhs) => parseWhenRestriction(parser, lhs, ["\\right", "\\}"]),
5815
+ serialize: (serializer, expr) => {
5816
+ const e = operand(expr, 1);
5817
+ const cond = operand(expr, 2);
5818
+ if (!e || !cond) return "";
5819
+ const clauses = operator(cond) === "And" ? operands(cond) ?? [] : [cond];
5820
+ const inner = clauses.map((c) => `\\left\\{${serializer.serialize(c)}\\right\\}`).join("");
5821
+ return `${serializer.serialize(e)}${inner}`;
5822
+ }
5823
+ },
5824
+ // When-restriction: bare `expr\{cond\}` → `When(expr, cond)`
5825
+ {
5826
+ kind: "postfix",
5827
+ precedence: 800,
5828
+ latexTrigger: ["\\{"],
5829
+ parse: (parser, lhs) => parseWhenRestriction(parser, lhs, ["\\}"])
5830
+ },
5705
5831
  {
5706
5832
  kind: "postfix",
5707
5833
  latexTrigger: ["_"],
@@ -5784,6 +5910,29 @@ var Compile = (() => {
5784
5910
  return "";
5785
5911
  }
5786
5912
  },
5913
+ // Additional triggers for Range: `...`, `\ldots`, and `\dots` are
5914
+ // equivalent to `..` when used as infix operators (e.g. `[1...9]`).
5915
+ // No `name` field here — names must be unique per the dictionary rules;
5916
+ // the first Range entry owns the name. When there is no LHS the symbol
5917
+ // entries near the top of the file still fire (ContinuationPlaceholder).
5918
+ {
5919
+ latexTrigger: [".", ".", "."],
5920
+ kind: "infix",
5921
+ precedence: 800,
5922
+ parse: parseRange
5923
+ },
5924
+ {
5925
+ latexTrigger: ["\\ldots"],
5926
+ kind: "infix",
5927
+ precedence: 800,
5928
+ parse: parseRange
5929
+ },
5930
+ {
5931
+ latexTrigger: ["\\dots"],
5932
+ kind: "infix",
5933
+ precedence: 800,
5934
+ parse: parseRange
5935
+ },
5787
5936
  {
5788
5937
  latexTrigger: [";"],
5789
5938
  kind: "infix",
@@ -5968,13 +6117,24 @@ var Compile = (() => {
5968
6117
  const args = operands(expr);
5969
6118
  if (!args || args.length < 2) return "";
5970
6119
  const body = args[0];
5971
- const indexing = args[1];
5972
- if (operator(indexing) === "Element") {
5973
- const index = operand(indexing, 1);
5974
- const range2 = operand(indexing, 2);
5975
- if (operator(range2) === "Range") {
5976
- const lo = operand(range2, 1);
5977
- const hi = operand(range2, 2);
6120
+ const elements = args.slice(1);
6121
+ const allElements = elements.every((e) => operator(e) === "Element");
6122
+ if (!allElements) {
6123
+ return joinLatex([
6124
+ "\\operatorname{Loop}(",
6125
+ serializer.serialize(body),
6126
+ ", ",
6127
+ serializer.serialize(elements[0]),
6128
+ ")"
6129
+ ]);
6130
+ }
6131
+ if (elements.length === 1) {
6132
+ const elem = elements[0];
6133
+ const index = operand(elem, 1);
6134
+ const coll = operand(elem, 2);
6135
+ if (operator(coll) === "Range") {
6136
+ const lo = operand(coll, 1);
6137
+ const hi = operand(coll, 2);
5978
6138
  return joinLatex([
5979
6139
  "\\text{for }",
5980
6140
  serializer.serialize(index),
@@ -5986,13 +6146,27 @@ var Compile = (() => {
5986
6146
  serializer.serialize(body)
5987
6147
  ]);
5988
6148
  }
6149
+ return joinLatex([
6150
+ serializer.serialize(body),
6151
+ " \\operatorname{for} ",
6152
+ serializer.serialize(index),
6153
+ " = ",
6154
+ serializer.serialize(coll)
6155
+ ]);
5989
6156
  }
6157
+ const bindings = elements.map((elem) => {
6158
+ const name = operand(elem, 1);
6159
+ const coll = operand(elem, 2);
6160
+ return joinLatex([
6161
+ serializer.serialize(name),
6162
+ " = ",
6163
+ serializer.serialize(coll)
6164
+ ]);
6165
+ }).join(", ");
5990
6166
  return joinLatex([
5991
- "\\operatorname{Loop}(",
5992
6167
  serializer.serialize(body),
5993
- ", ",
5994
- serializer.serialize(indexing),
5995
- ")"
6168
+ " \\operatorname{for} ",
6169
+ bindings
5996
6170
  ]);
5997
6171
  }
5998
6172
  },
@@ -6025,6 +6199,18 @@ var Compile = (() => {
6025
6199
  precedence: 245,
6026
6200
  parse: (parser, until) => parseForExpression(parser, until)
6027
6201
  },
6202
+ // \operatorname{for} as postfix infix (list comprehension):
6203
+ // `body \operatorname{for} x = L_1, y = L_2`
6204
+ // Precedence 19 — just below comma (20) so the body is allowed to use
6205
+ // any operator (including comma sequencing) up to the keyword, and the
6206
+ // bindings can be comma-separated below us.
6207
+ {
6208
+ symbolTrigger: "for",
6209
+ kind: "infix",
6210
+ associativity: "none",
6211
+ precedence: 19,
6212
+ parse: (parser, lhs, until) => parseForComprehension(parser, lhs, until)
6213
+ },
6028
6214
  // \operatorname{break}
6029
6215
  {
6030
6216
  symbolTrigger: "break",
@@ -6229,7 +6415,10 @@ var Compile = (() => {
6229
6415
  if (!sym2 || !parser.getSymbolType(sym2).matches("function")) return null;
6230
6416
  parser.addBoundary([")"]);
6231
6417
  const expr = parser.parseExpression(until);
6232
- if (!parser.matchBoundary()) return null;
6418
+ if (!parser.matchBoundary()) {
6419
+ parser.removeBoundary();
6420
+ return null;
6421
+ }
6233
6422
  if (!parser.match("<}>")) return null;
6234
6423
  return ["Derivative", lhs, expr];
6235
6424
  }
@@ -6670,7 +6859,12 @@ var Compile = (() => {
6670
6859
  if (isEmptySequence(body)) return ["List"];
6671
6860
  const h = operator(body);
6672
6861
  if (h === "Range" || h === "Linspace") return body;
6673
- if (h === "Sequence") return ["List", ...operands(body)];
6862
+ if (h === "Sequence") {
6863
+ const elems = operands(body);
6864
+ const inferred = tryInferRangeFromElements(elems, parser);
6865
+ if (inferred) return inferred;
6866
+ return ["List", ...elems];
6867
+ }
6674
6868
  if (h === "Delimiter") {
6675
6869
  const delim = stringValue(operand(body, 2)) ?? "...";
6676
6870
  if (delim === ";" || delim === ".;.") {
@@ -6683,12 +6877,37 @@ var Compile = (() => {
6683
6877
  }
6684
6878
  if (delim === "," || delim === ".,.") {
6685
6879
  body = operand(body, 1);
6686
- if (operator(body) === "Sequence") return ["List", ...operands(body)];
6880
+ if (operator(body) === "Sequence") {
6881
+ const elems = operands(body);
6882
+ const inferred = tryInferRangeFromElements(elems, parser);
6883
+ if (inferred) return inferred;
6884
+ return ["List", ...elems];
6885
+ }
6687
6886
  return ["List", body ?? "Nothing"];
6688
6887
  }
6689
6888
  }
6690
6889
  return ["List", body];
6691
6890
  }
6891
+ function tryInferRangeFromElements(elems, parser) {
6892
+ if (elems.length < 4) return null;
6893
+ const penultimate = elems[elems.length - 2];
6894
+ if (symbol(penultimate) !== "ContinuationPlaceholder") return null;
6895
+ const samples = elems.slice(0, -2);
6896
+ const endExpr = elems[elems.length - 1];
6897
+ if (samples.length < 2) return null;
6898
+ const sampleNums = samples.map(machineValue);
6899
+ if (sampleNums.some((n) => n === null)) return null;
6900
+ const nums = sampleNums;
6901
+ const step = nums[nums.length - 1] - nums[nums.length - 2];
6902
+ const tol = parser.options.tolerance;
6903
+ if (Math.abs(step) < tol)
6904
+ return parser.error("degenerate-range-step", parser.index);
6905
+ for (let i = 1; i < nums.length; i++) {
6906
+ if (Math.abs(nums[i] - nums[i - 1] - step) > tol)
6907
+ return parser.error("inconsistent-range-samples", parser.index);
6908
+ }
6909
+ return ["Range", nums[0], endExpr, step];
6910
+ }
6692
6911
  function serializeList(serializer, expr) {
6693
6912
  if (nops(expr) > 1 && operands(expr).every((x) => {
6694
6913
  const op = operator(x);
@@ -6940,6 +7159,38 @@ var Compile = (() => {
6940
7159
  ["Element", index, ["Range", lower, upper]]
6941
7160
  ];
6942
7161
  }
7162
+ function parseForComprehension(parser, lhs, until) {
7163
+ const bindingTerminator = {
7164
+ minPrec: 21,
7165
+ // Above comma (20) and ; (19), so `x = L_1` is captured whole
7166
+ condition: (p) => {
7167
+ if (until?.condition?.(p)) return true;
7168
+ const saved = p.index;
7169
+ p.skipVisualSpace();
7170
+ const isComma = p.peek === ",";
7171
+ p.index = saved;
7172
+ if (isComma) return true;
7173
+ if (peekKeyword(p, "where")) return true;
7174
+ if (peekKeyword(p, "with")) return true;
7175
+ return false;
7176
+ }
7177
+ };
7178
+ const elements = [];
7179
+ do {
7180
+ parser.skipVisualSpace();
7181
+ const binding = parser.parseExpression(bindingTerminator);
7182
+ if (binding === null) break;
7183
+ const op = operator(binding);
7184
+ if (op !== "Equal" && op !== "Assign") return null;
7185
+ const name = operand(binding, 1);
7186
+ const list = operand(binding, 2);
7187
+ if (!name || !list) return null;
7188
+ elements.push(["Element", name, list]);
7189
+ parser.skipVisualSpace();
7190
+ } while (parser.match(","));
7191
+ if (elements.length === 0) return null;
7192
+ return ["Loop", lhs, ...elements];
7193
+ }
6943
7194
  function parseWhereExpression(parser, lhs, until) {
6944
7195
  const bindingTerminator = {
6945
7196
  minPrec: 21,
@@ -6962,6 +7213,25 @@ var Compile = (() => {
6962
7213
  parser.skipVisualSpace();
6963
7214
  } while (parser.match(","));
6964
7215
  if (bindings.length === 0) return null;
7216
+ const forStart = parser.index;
7217
+ if (matchKeyword(parser, "for")) {
7218
+ const loop = parseForComprehension(parser, lhs, until);
7219
+ if (loop) {
7220
+ const block2 = [];
7221
+ for (const b of bindings) {
7222
+ const normalized = normalizeLocalAssign(b);
7223
+ if (operator(normalized) === "Assign") {
7224
+ block2.push(["Declare", operand(normalized, 1)]);
7225
+ block2.push(normalized);
7226
+ } else {
7227
+ block2.push(normalized);
7228
+ }
7229
+ }
7230
+ block2.push(loop);
7231
+ return ["Block", ...block2];
7232
+ }
7233
+ parser.index = forStart;
7234
+ }
6965
7235
  const block = [];
6966
7236
  for (const b of bindings) {
6967
7237
  const normalized = normalizeLocalAssign(b);
@@ -7175,6 +7445,17 @@ var Compile = (() => {
7175
7445
  const upperExpr = openRight ? ["Open", upper] : upper;
7176
7446
  return ["Interval", lowerExpr, upperExpr];
7177
7447
  }
7448
+ var COMPARISON_HEADS = /* @__PURE__ */ new Set([
7449
+ "Less",
7450
+ "LessEqual",
7451
+ "Greater",
7452
+ "GreaterEqual",
7453
+ "Equal",
7454
+ "NotEqual",
7455
+ "And",
7456
+ "Or",
7457
+ "Not"
7458
+ ]);
7178
7459
  var DEFINITIONS_SETS = [
7179
7460
  //
7180
7461
  // Constants
@@ -7433,18 +7714,58 @@ var Compile = (() => {
7433
7714
  closeTrigger: "}",
7434
7715
  parse: (_parser, body) => {
7435
7716
  if (isEmptySequence(body)) return "EmptySet";
7717
+ if (operator(body) == "Delimiter" && stringValue(operand(body, 2)) === ",") {
7718
+ body = operand(body, 1);
7719
+ }
7436
7720
  const h = operator(body);
7437
- if (h === "Divides" || h === "Colon") {
7721
+ if (h === "Divides") {
7438
7722
  const expr = operand(body, 1);
7439
7723
  const condition = operand(body, 2);
7440
7724
  if (expr !== null && condition !== null)
7441
7725
  return ["Set", expr, ["Condition", condition]];
7442
7726
  }
7443
- if (operator(body) == "Delimiter" && stringValue(operand(body, 2)) === ",") {
7444
- body = operand(body, 1);
7727
+ if (h === "Colon") {
7728
+ const lhs = operand(body, 1);
7729
+ const rhs = operand(body, 2);
7730
+ if (lhs !== null && rhs !== null) {
7731
+ const lhsOp = operator(lhs);
7732
+ if (lhsOp !== null && COMPARISON_HEADS.has(lhsOp)) {
7733
+ return ["Which", lhs, rhs];
7734
+ }
7735
+ return ["Set", lhs, ["Condition", rhs]];
7736
+ }
7445
7737
  }
7446
- if (operator(body) !== "Sequence") return ["Set", body];
7447
- return ["Set", ...operands(body)];
7738
+ if (h === "Sequence") {
7739
+ const elements = operands(body);
7740
+ const colonElements = elements.filter((el) => operator(el) === "Colon");
7741
+ const allPiecewise = colonElements.length > 0 && colonElements.every((el) => {
7742
+ const lhs = operand(el, 1);
7743
+ const lhsOp = lhs !== null ? operator(lhs) : null;
7744
+ return lhsOp !== null && COMPARISON_HEADS.has(lhsOp);
7745
+ });
7746
+ if (allPiecewise) {
7747
+ const whichOps = [];
7748
+ for (let i = 0; i < elements.length; i++) {
7749
+ const el = elements[i];
7750
+ if (operator(el) === "Colon") {
7751
+ const cond = operand(el, 1);
7752
+ const val = operand(el, 2);
7753
+ if (cond === null || val === null) {
7754
+ return ["Set", ...elements];
7755
+ }
7756
+ whichOps.push(cond, val);
7757
+ } else {
7758
+ if (i !== elements.length - 1) {
7759
+ return ["Set", ...elements];
7760
+ }
7761
+ whichOps.push("True", el);
7762
+ }
7763
+ }
7764
+ return ["Which", ...whichOps];
7765
+ }
7766
+ return ["Set", ...elements];
7767
+ }
7768
+ return ["Set", body];
7448
7769
  },
7449
7770
  serialize: (serializer, expr) => {
7450
7771
  if (nops(expr) === 2 && operator(operand(expr, 2)) === "Condition") {
@@ -9418,7 +9739,8 @@ var Compile = (() => {
9418
9739
  minPrec: MULTIPLICATION_PRECEDENCE,
9419
9740
  condition: (parser2) => trigCommands[parser2.peek] || (until?.condition?.(parser2) ?? false)
9420
9741
  });
9421
- const appliedFn = args === null ? fn : typeof fn === "string" ? [fn, ...args] : ["Apply", fn, ...args];
9742
+ const head = fn === "Arctan" && args?.length === 2 ? "Arctan2" : fn;
9743
+ const appliedFn = args === null ? fn : typeof head === "string" ? [head, ...args] : ["Apply", head, ...args];
9422
9744
  return sup === null ? appliedFn : ["Power", appliedFn, sup];
9423
9745
  };
9424
9746
  }
@@ -11541,10 +11863,17 @@ var Compile = (() => {
11541
11863
  // The capitalized library entries already exist; these are pure parse
11542
11864
  // aliases so the lowercase names don't land in `unsupported-operator`.
11543
11865
  // ---------------------------------------------------------------------------
11866
+ { latexTrigger: "\\operatorname{count}", parse: "Length" },
11544
11867
  { latexTrigger: "\\operatorname{random}", parse: "Random" },
11545
11868
  { latexTrigger: "\\operatorname{shuffle}", parse: "Shuffle" },
11546
11869
  { latexTrigger: "\\operatorname{repeat}", parse: "Repeat" },
11547
11870
  { latexTrigger: "\\operatorname{join}", parse: "Join" },
11871
+ { latexTrigger: "\\operatorname{range}", parse: "Range" },
11872
+ // Note: `\operatorname{with}` (Desmos's local-binding clause) is intentionally
11873
+ // NOT registered here. Use the math-notation equivalent `\operatorname{where}`
11874
+ // (with `\coloneq` for bindings), or register `with` as a custom dictionary
11875
+ // entry at the integration layer — see the "Desmos-Specific Syntax — Prefer
11876
+ // Custom LaTeX Dictionary" section in COMPUTE_ENGINE.md for a worked example.
11548
11877
  // ---------------------------------------------------------------------------
11549
11878
  // Geometric primitive heads. Registered as known typed heads so consumers
11550
11879
  // can branch on the operator name; CE itself doesn't render them. The
@@ -12735,6 +13064,15 @@ ${lines.join("\n")}`;
12735
13064
  return void 0;
12736
13065
  }
12737
13066
 
13067
+ // src/compute-engine/numerics/random.ts
13068
+ function deterministicRandom(seed) {
13069
+ const v = Math.sin(seed * 12.9898) * 43758.5453;
13070
+ return v - Math.floor(v);
13071
+ }
13072
+ function nextSeed(seed) {
13073
+ return seed + 0.6180339887498949;
13074
+ }
13075
+
12738
13076
  // src/compute-engine/boxed-expression/canonical-utils.ts
12739
13077
  function canonical(ce, xs, scope) {
12740
13078
  if (xs.every((x) => x.isCanonical)) return xs;
@@ -12784,6 +13122,19 @@ ${lines.join("\n")}`;
12784
13122
  indexWhere: void 0
12785
13123
  }
12786
13124
  },
13125
+ Length: {
13126
+ description: "Number of elements in a collection. Returns undefined for non-collections and for infinite collections.",
13127
+ complexity: 4e3,
13128
+ signature: "(any) -> integer",
13129
+ type: () => "integer",
13130
+ evaluate: ([xs], { engine }) => {
13131
+ if (!xs.isCollection) return void 0;
13132
+ if (xs.isEmptyCollection) return engine.Zero;
13133
+ const n = xs.count;
13134
+ if (n === void 0 || !isFinite(n)) return void 0;
13135
+ return engine.number(n);
13136
+ }
13137
+ },
12787
13138
  Tuple: {
12788
13139
  description: "A fixed number of heterogeneous elements",
12789
13140
  complexity: 8200,
@@ -12836,7 +13187,11 @@ ${lines.join("\n")}`;
12836
13187
  //
12837
13188
  Range: {
12838
13189
  complexity: 8200,
12839
- signature: "(number, number?, step: number?) -> indexed_collection<integer>",
13190
+ signature: "(number, number?, step: number?) -> indexed_collection<number>",
13191
+ type: (ops) => {
13192
+ const allInt = ops.every((op) => op.isInteger);
13193
+ return allInt ? parseType("indexed_collection<integer>") : parseType("indexed_collection<number>");
13194
+ },
12840
13195
  canonical: (ops, { engine: ce }) => {
12841
13196
  if (ops.length === 0) return null;
12842
13197
  if (ops.length === 1) return ce._fn("Range", [ce.One, ops[0].canonical]);
@@ -12860,19 +13215,26 @@ ${lines.join("\n")}`;
12860
13215
  const [lower, upper, step] = range(expr);
12861
13216
  if (step === 0) return 0;
12862
13217
  if (!isFinite(lower) || !isFinite(upper)) return Infinity;
12863
- return 1 + Math.max(0, Math.floor((upper - lower) / step));
13218
+ return Math.max(0, Math.floor((upper - lower) / step) + 1);
12864
13219
  },
12865
13220
  contains: (expr, target) => {
12866
- if (!target.type.matches("integer")) return false;
12867
13221
  const t = target.re;
13222
+ if (!isFinite(t)) return false;
12868
13223
  const [lower, upper, step] = range(expr);
12869
13224
  if (step === 0) return false;
12870
- if (step > 0) return t >= lower && t <= upper;
12871
- return t <= lower && t >= upper;
13225
+ if (step > 0) {
13226
+ if (t < lower || t > upper) return false;
13227
+ } else {
13228
+ if (t > lower || t < upper) return false;
13229
+ }
13230
+ const k = (t - lower) / step;
13231
+ const tol = expr.engine.tolerance;
13232
+ const kRounded = Math.round(k);
13233
+ return kRounded >= 0 && Math.abs(k - kRounded) < tol;
12872
13234
  },
12873
13235
  iterator: (expr) => {
12874
13236
  const [lower, upper, step] = range(expr);
12875
- const maxCount = step === 0 ? 0 : Math.floor((upper - lower) / step) + 1;
13237
+ const maxCount = step === 0 ? 0 : Math.max(0, Math.floor((upper - lower) / step) + 1);
12876
13238
  let index = 1;
12877
13239
  return {
12878
13240
  next: () => {
@@ -12890,7 +13252,9 @@ ${lines.join("\n")}`;
12890
13252
  at: (expr, index) => {
12891
13253
  if (typeof index !== "number") return void 0;
12892
13254
  const [lower, upper, step] = range(expr);
12893
- if (index < 1 || index > 1 + (upper - lower) / step) return void 0;
13255
+ if (step === 0) return void 0;
13256
+ const maxCount = Math.max(0, Math.floor((upper - lower) / step) + 1);
13257
+ if (index < 1 || index > maxCount) return void 0;
12894
13258
  return expr.engine.number(lower + step * (index - 1));
12895
13259
  },
12896
13260
  indexWhere: void 0,
@@ -12915,7 +13279,13 @@ ${lines.join("\n")}`;
12915
13279
  if (step > 0) return lower <= upper ? "positive" : "negative";
12916
13280
  return lower >= upper ? "positive" : "negative";
12917
13281
  },
12918
- elttype: (_expr) => "finite_integer"
13282
+ elttype: (expr) => {
13283
+ if (!isFunction2(expr)) return "finite_integer";
13284
+ for (let i = 1; i <= expr.nops; i++) {
13285
+ if (!expr[`op${i}`].isInteger) return "finite_real";
13286
+ }
13287
+ return "finite_integer";
13288
+ }
12919
13289
  }
12920
13290
  },
12921
13291
  Interval: {
@@ -13018,10 +13388,12 @@ ${lines.join("\n")}`;
13018
13388
  const upper = expr.op2.re;
13019
13389
  let count = expr.op3.re;
13020
13390
  if (!isFinite(count)) count = DEFAULT_LINSPACE_COUNT;
13391
+ count = Math.floor(count);
13021
13392
  if (!isFinite(lower) || !isFinite(upper)) return void 0;
13022
13393
  if (index < 1 || index > count) return void 0;
13394
+ if (count === 1) return expr.engine.number(lower);
13023
13395
  return expr.engine.number(
13024
- lower + (upper - lower) * (index - 1) / count
13396
+ lower + (upper - lower) * (index - 1) / (count - 1)
13025
13397
  );
13026
13398
  },
13027
13399
  iterator: (expr) => {
@@ -13040,6 +13412,8 @@ ${lines.join("\n")}`;
13040
13412
  !isFinite(expr.op3.re) ? DEFAULT_LINSPACE_COUNT : expr.op3.re
13041
13413
  );
13042
13414
  }
13415
+ totalCount = Math.floor(totalCount);
13416
+ const denom = totalCount > 1 ? totalCount - 1 : 1;
13043
13417
  let index = 1;
13044
13418
  return {
13045
13419
  next: () => {
@@ -13048,7 +13422,7 @@ ${lines.join("\n")}`;
13048
13422
  index += 1;
13049
13423
  return {
13050
13424
  value: expr.engine.number(
13051
- lower + (upper - lower) * (index - 1 - 1) / totalCount
13425
+ lower + (upper - lower) * (index - 1 - 1) / denom
13052
13426
  ),
13053
13427
  done: false
13054
13428
  };
@@ -13064,9 +13438,14 @@ ${lines.join("\n")}`;
13064
13438
  if (t < lower || t > upper) return false;
13065
13439
  let count = expr.op3.re;
13066
13440
  if (!isFinite(count)) count = DEFAULT_LINSPACE_COUNT;
13441
+ count = Math.floor(count);
13067
13442
  if (count === 0) return false;
13068
- const step = (upper - lower) / count;
13069
- return (t - lower) % step === 0;
13443
+ if (count === 1) return t === lower;
13444
+ const step = (upper - lower) / (count - 1);
13445
+ const k = (t - lower) / step;
13446
+ const tol = expr.engine.tolerance;
13447
+ const kRounded = Math.round(k);
13448
+ return kRounded >= 0 && kRounded <= count - 1 && Math.abs(k - kRounded) < tol;
13070
13449
  }
13071
13450
  }
13072
13451
  },
@@ -13391,10 +13770,12 @@ ${lines.join("\n")}`;
13391
13770
  description: [
13392
13771
  "Access an element of an indexed collection.",
13393
13772
  "If the index is negative, it is counted from the end.",
13394
- "Multiple indices can be provided to access nested collections (e.g., matrices)."
13773
+ "Multiple indices can be provided to access nested collections (e.g., matrices).",
13774
+ "If the index is a finite collection of booleans, returns the elements where the mask is True.",
13775
+ "If the index is a finite collection of integers, returns the elements at those indices."
13395
13776
  ],
13396
13777
  complexity: 8200,
13397
- signature: "(value: indexed_collection, index: (number|string)+) -> unknown",
13778
+ signature: "(value: indexed_collection, index: (number|string|indexed_collection)+) -> unknown",
13398
13779
  type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? collectionElementType(xs.type.type) ?? "any",
13399
13780
  evaluate: (ops, { engine: ce }) => {
13400
13781
  let expr = ops[0];
@@ -13405,12 +13786,39 @@ ${lines.join("\n")}`;
13405
13786
  if (!at) return void 0;
13406
13787
  const opAtIndex = ops[index];
13407
13788
  const s = isString(opAtIndex) ? opAtIndex.string : void 0;
13408
- if (s !== void 0) expr = at(expr, s) ?? ce.Nothing;
13409
- else {
13410
- const i = ops[index].re;
13411
- if (!Number.isInteger(i)) return void 0;
13412
- expr = at(expr, i) ?? ce.Nothing;
13789
+ if (s !== void 0) {
13790
+ expr = at(expr, s) ?? ce.Nothing;
13791
+ index += 1;
13792
+ continue;
13413
13793
  }
13794
+ if (opAtIndex.isCollection && opAtIndex.isFiniteCollection) {
13795
+ const indices = Array.from(opAtIndex.each());
13796
+ const isMask = indices.every((m) => {
13797
+ const name = sym(m);
13798
+ return name === "True" || name === "False";
13799
+ });
13800
+ const picked = [];
13801
+ if (isMask) {
13802
+ indices.forEach((m, i2) => {
13803
+ if (sym(m) !== "True") return;
13804
+ const v = at(expr, i2 + 1);
13805
+ if (v !== void 0) picked.push(v);
13806
+ });
13807
+ } else {
13808
+ for (const m of indices) {
13809
+ const k = m.re;
13810
+ if (!Number.isInteger(k)) return void 0;
13811
+ const v = at(expr, k);
13812
+ if (v !== void 0) picked.push(v);
13813
+ }
13814
+ }
13815
+ expr = ce._fn("List", picked);
13816
+ index += 1;
13817
+ continue;
13818
+ }
13819
+ const i = opAtIndex.re;
13820
+ if (!Number.isInteger(i)) return void 0;
13821
+ expr = at(expr, i) ?? ce.Nothing;
13414
13822
  index += 1;
13415
13823
  }
13416
13824
  return expr;
@@ -13421,7 +13829,7 @@ ${lines.join("\n")}`;
13421
13829
  description: ["Return `n` elements from a collection."],
13422
13830
  complexity: 8200,
13423
13831
  signature: "(xs: indexed_collection, count: number) -> indexed_collection",
13424
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
13832
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
13425
13833
  evaluate: (ops, { engine, materialization: eager }) => {
13426
13834
  if (!eager) return void 0;
13427
13835
  const takeExpr = engine._fn("Take", ops);
@@ -13468,7 +13876,7 @@ ${lines.join("\n")}`;
13468
13876
  description: ["Return the collection without the first n elements."],
13469
13877
  complexity: 8200,
13470
13878
  signature: "(xs: indexed_collection, count: number) -> indexed_collection",
13471
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
13879
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
13472
13880
  collection: {
13473
13881
  isLazy: (_expr) => true,
13474
13882
  count: (expr) => {
@@ -13513,15 +13921,45 @@ ${lines.join("\n")}`;
13513
13921
  },
13514
13922
  First: {
13515
13923
  complexity: 8200,
13516
- signature: "(collection) -> any",
13924
+ signature: "(any) -> any",
13517
13925
  type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? "any",
13518
- evaluate: ([xs], { engine: ce }) => xs.at(1) ?? ce.Nothing
13926
+ evaluate: ([xs], { engine: ce }) => {
13927
+ if (!xs.isCollection)
13928
+ return ce.error([
13929
+ "incompatible-type",
13930
+ `'collection'`,
13931
+ xs.type.toString()
13932
+ ]);
13933
+ return xs.at(1) ?? ce.Nothing;
13934
+ }
13519
13935
  },
13520
13936
  Second: {
13521
13937
  complexity: 8200,
13522
- signature: "(collection) -> any",
13938
+ signature: "(any) -> any",
13523
13939
  type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? "any",
13524
- evaluate: ([xs], { engine: ce }) => xs.at(2) ?? ce.Nothing
13940
+ evaluate: ([xs], { engine: ce }) => {
13941
+ if (!xs.isCollection)
13942
+ return ce.error([
13943
+ "incompatible-type",
13944
+ `'collection'`,
13945
+ xs.type.toString()
13946
+ ]);
13947
+ return xs.at(2) ?? ce.Nothing;
13948
+ }
13949
+ },
13950
+ Third: {
13951
+ complexity: 8200,
13952
+ signature: "(any) -> any",
13953
+ type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? "any",
13954
+ evaluate: ([xs], { engine: ce }) => {
13955
+ if (!xs.isCollection)
13956
+ return ce.error([
13957
+ "incompatible-type",
13958
+ `'collection'`,
13959
+ xs.type.toString()
13960
+ ]);
13961
+ return xs.at(3) ?? ce.Nothing;
13962
+ }
13525
13963
  },
13526
13964
  Last: {
13527
13965
  complexity: 8200,
@@ -13634,7 +14072,9 @@ ${lines.join("\n")}`;
13634
14072
  ],
13635
14073
  complexity: 8200,
13636
14074
  signature: "(value: indexed_collection, start: number, end: number) -> list",
13637
- type: ([xs]) => parseType(`list<${collectionElementType(xs.type.type)}>`),
14075
+ type: ([xs]) => parseType(
14076
+ `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`
14077
+ ),
13638
14078
  collection: {
13639
14079
  isLazy: (_expr) => true,
13640
14080
  count: (expr) => {
@@ -13966,16 +14406,26 @@ ${lines.join("\n")}`;
13966
14406
  },
13967
14407
  // Randomize the order of the elements in the collection.
13968
14408
  Shuffle: {
13969
- description: "Randomize the order of the elements in the collection.",
14409
+ description: "Randomize the order of the elements in the collection. With an optional `seed` argument, the shuffle is deterministic.",
13970
14410
  complexity: 8200,
13971
- signature: "(indexed_collection) -> indexed_collection",
14411
+ signature: "(indexed_collection, real?) -> indexed_collection",
13972
14412
  type: (ops) => ops[0].type,
13973
- evaluate: ([xs], { engine: ce }) => {
14413
+ evaluate: ([xs, seedOp], { engine: ce }) => {
13974
14414
  if (!xs.isFiniteCollection) return void 0;
13975
14415
  const data = Array.from(xs.each());
13976
- for (let i = data.length - 1; i > 0; i--) {
13977
- const j = Math.floor(Math.random() * (i + 1));
13978
- [data[i], data[j]] = [data[j], data[i]];
14416
+ const seed = seedOp?.re;
14417
+ if (seed !== void 0 && !Number.isNaN(seed)) {
14418
+ let s = seed;
14419
+ for (let i = data.length - 1; i > 0; i--) {
14420
+ const j = Math.floor(deterministicRandom(s) * (i + 1));
14421
+ [data[i], data[j]] = [data[j], data[i]];
14422
+ s = nextSeed(s);
14423
+ }
14424
+ } else {
14425
+ for (let i = data.length - 1; i > 0; i--) {
14426
+ const j = Math.floor(Math.random() * (i + 1));
14427
+ [data[i], data[j]] = [data[j], data[i]];
14428
+ }
13979
14429
  }
13980
14430
  return ce.function(xs.operator, data);
13981
14431
  }
@@ -14042,7 +14492,9 @@ ${lines.join("\n")}`;
14042
14492
  if (t === "string")
14043
14493
  return parseType(`tuple<list<string>, list<integer>>`);
14044
14494
  return parseType(
14045
- `tuple<list<${collectionElementType(t)}>, list<integer>>`
14495
+ `tuple<list<${typeToString(
14496
+ collectionElementType(t) ?? "any"
14497
+ )}>, list<integer>>`
14046
14498
  );
14047
14499
  },
14048
14500
  evaluate: (ops, { engine: ce }) => {
@@ -14058,7 +14510,7 @@ ${lines.join("\n")}`;
14058
14510
  description: "Return a list of the unique elements of the collection.",
14059
14511
  complexity: 8200,
14060
14512
  signature: "(collection) -> list",
14061
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
14513
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
14062
14514
  evaluate: (ops, { engine: ce }) => {
14063
14515
  if (!ops[0].isFiniteCollection) return void 0;
14064
14516
  const [values, _counts] = tally(ops[0]);
@@ -14070,7 +14522,7 @@ ${lines.join("\n")}`;
14070
14522
  wikidata: "Q381060",
14071
14523
  complexity: 8200,
14072
14524
  signature: "(collection, integer | function) -> list",
14073
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
14525
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
14074
14526
  evaluate: ([xs, arg], { engine: ce }) => {
14075
14527
  if (!xs.isFiniteCollection) return void 0;
14076
14528
  const k = toInteger(arg);
@@ -14244,32 +14696,74 @@ ${lines.join("\n")}`;
14244
14696
  }
14245
14697
  }
14246
14698
  },
14247
- // Repeat(x) -> [x, x, ...]
14248
- // This is an infinite series. Can use Take(Repeat(x), n) to get a finite series
14249
- // x is evaluated once. Although could use Hold()?
14250
- // So that First(Repeat(Hold(Random(5))), 10) would return 10 random numbers...
14699
+ // Repeat(x) -> [x, x, ...] — infinite sequence
14700
+ // Repeat(x, n) -> [x, x, ..., x] — finite list of n copies
14251
14701
  Repeat: {
14252
- description: "Produce an infinite sequence by repeating a single value.",
14702
+ 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.",
14253
14703
  complexity: 8200,
14254
- signature: "(value: any) -> list",
14704
+ signature: "(value: any, count: integer?) -> list",
14705
+ evaluate: (ops, { engine }) => {
14706
+ if (ops.length !== 2) return void 0;
14707
+ const raw = toInteger(ops[1]);
14708
+ if (raw === null) return void 0;
14709
+ const n = Math.max(0, raw);
14710
+ if (n > engine.maxCollectionSize) return void 0;
14711
+ return engine._fn("List", Array(n).fill(ops[0]));
14712
+ },
14255
14713
  collection: {
14256
- isLazy: (_expr) => true,
14257
- count: () => Infinity,
14258
- isEmpty: (_expr) => false,
14259
- // Never empty
14260
- isFinite: () => false,
14261
- // Infinite collection
14714
+ isLazy: (expr) => isFunction2(expr) && expr.ops?.length === 1,
14715
+ count: (expr) => {
14716
+ if (!isFunction2(expr)) return void 0;
14717
+ if (expr.ops?.length === 2) {
14718
+ const n = toInteger(expr.op2);
14719
+ return n !== null ? Math.max(0, n) : void 0;
14720
+ }
14721
+ return Infinity;
14722
+ },
14723
+ isEmpty: (expr) => {
14724
+ if (!isFunction2(expr)) return void 0;
14725
+ if (expr.ops?.length === 2) {
14726
+ const n = toInteger(expr.op2);
14727
+ return n !== null ? n <= 0 : void 0;
14728
+ }
14729
+ return false;
14730
+ },
14731
+ isFinite: (expr) => isFunction2(expr) && expr.ops?.length === 2,
14262
14732
  contains: (expr, target) => {
14263
14733
  if (!isFunction2(expr)) return false;
14734
+ if (expr.ops?.length === 2) {
14735
+ const n = toInteger(expr.op2);
14736
+ if (n !== null && n <= 0) return false;
14737
+ }
14264
14738
  return expr.op1.isSame(target);
14265
14739
  },
14266
14740
  iterator: (expr) => {
14267
14741
  if (!isFunction2(expr))
14268
14742
  return { next: () => ({ value: void 0, done: true }) };
14743
+ if (expr.ops?.length === 2) {
14744
+ const n = toInteger(expr.op2);
14745
+ if (n === null) {
14746
+ return { next: () => ({ value: void 0, done: true }) };
14747
+ }
14748
+ const count = Math.max(0, n);
14749
+ let i = 0;
14750
+ return {
14751
+ next: () => i++ < count ? { value: expr.op1, done: false } : { value: void 0, done: true }
14752
+ };
14753
+ }
14269
14754
  return { next: () => ({ value: expr.op1, done: false }) };
14270
14755
  },
14271
- at: (expr, _index) => {
14756
+ // at is 1-based (consistent with Range, Take, and other collection handlers)
14757
+ at: (expr, index) => {
14272
14758
  if (!isFunction2(expr)) return void 0;
14759
+ if (typeof index !== "number") return void 0;
14760
+ if (expr.ops?.length === 2) {
14761
+ const n = toInteger(expr.op2);
14762
+ const count = n !== null ? Math.max(0, n) : 0;
14763
+ if (index < 1 || index > count) return void 0;
14764
+ } else {
14765
+ if (index < 1) return void 0;
14766
+ }
14273
14767
  return expr.op1;
14274
14768
  }
14275
14769
  }
@@ -14500,17 +14994,14 @@ ${lines.join("\n")}`;
14500
14994
  if (!isFunction2(expr)) return [1, 0, 0];
14501
14995
  if (expr.nops === 0) return [1, 0, 0];
14502
14996
  let op1 = expr.op1.re;
14503
- if (!isFinite(op1)) op1 = 1;
14504
- else op1 = Math.round(op1);
14997
+ if (!isFinite(op1) && !op1) op1 = 1;
14505
14998
  if (expr.nops === 1) return [1, op1, 1];
14506
14999
  let op2 = expr.op2.re;
14507
15000
  if (!isFinite(op2) && !op2) op2 = 1;
14508
- else if (isFinite(op2)) op2 = Math.round(op2);
14509
- if (expr.nops === 2) return [op1, op2, op2 > op1 ? 1 : -1];
15001
+ if (expr.nops === 2) return [op1, op2, op2 >= op1 ? 1 : -1];
14510
15002
  let op3 = expr.op3.re;
14511
- if (!isFinite(op3)) op3 = 1;
14512
- else op3 = Math.abs(Math.round(op3));
14513
- return [op1, op2, op1 < op2 ? op3 : -op3];
15003
+ if (!isFinite(op3) && !op3) op3 = 1;
15004
+ return [op1, op2, op3];
14514
15005
  }
14515
15006
  function canonicalList(ops, { engine: ce }) {
14516
15007
  const op1 = ops[0];
@@ -14859,6 +15350,23 @@ ${lines.join("\n")}`;
14859
15350
  };
14860
15351
  return compilePair(0);
14861
15352
  }
15353
+ if (h === "When") {
15354
+ if (args.length !== 2)
15355
+ throw new Error("When: expected exactly 2 arguments (expr, cond)");
15356
+ const fn2 = target.functions?.(h);
15357
+ if (fn2) {
15358
+ if (typeof fn2 === "function") {
15359
+ return fn2(args, (expr) => _BaseCompiler.compile(expr, target), target);
15360
+ }
15361
+ return `${fn2}(${args.map((x) => _BaseCompiler.compile(x, target)).join(", ")})`;
15362
+ }
15363
+ if (isSymbol2(args[1], "True"))
15364
+ return `(${_BaseCompiler.compile(args[0], target)})`;
15365
+ if (isSymbol2(args[1], "False")) return "NaN";
15366
+ const val = _BaseCompiler.compile(args[0], target);
15367
+ const cond = _BaseCompiler.compile(args[1], target);
15368
+ return `((${cond}) ? (${val}) : NaN)`;
15369
+ }
14862
15370
  if (h === "Block") {
14863
15371
  return _BaseCompiler.compileBlock(args, target);
14864
15372
  }
@@ -14933,17 +15441,98 @@ ${lines.join("\n")}`;
14933
15441
  )}${target.ws("\n")}})()`;
14934
15442
  }
14935
15443
  /**
14936
- * Compile a Loop expression with Element(index, Range(lo, hi)) indexing.
14937
- * Generates: (() => { for (let i = lo; i <= hi; i++) { body } })()
15444
+ * Compile a Loop expression.
15445
+ *
15446
+ * Two forms are supported:
15447
+ *
15448
+ * 1. **Imperative / single-Element form** (existing behaviour):
15449
+ * `Loop(body, Element(i, Range(lo, hi)))`
15450
+ * Generates a raw `for (let i = lo; i <= hi; i++) { body }` loop wrapped
15451
+ * in an IIFE. The loop counter is always a plain number. For targets
15452
+ * that wrap numeric values (e.g. interval-js uses `_IA.point()`),
15453
+ * references to the loop index inside the body are re-wrapped via
15454
+ * `target.number`. `break` / `continue` / `return` are preserved.
15455
+ *
15456
+ * 2. **Comprehension / variadic-Element form** (new):
15457
+ * `Loop(body, Element(x, coll1), Element(y, coll2), …)`
15458
+ * When two or more `Element` clauses are present — or when the single
15459
+ * Element's collection is not a `Range` — the loop is compiled as a
15460
+ * comprehension that collects results into an array. Each clause
15461
+ * produces a `for (const name of collection)` loop, nested
15462
+ * outermost-to-innermost, and the innermost body pushes into `result`.
15463
+ *
15464
+ * Example output (JS):
15465
+ * ```js
15466
+ * (() => { const result = [];
15467
+ * for (const x of [1,2]) { for (const y of [3,4]) { result.push(body); } }
15468
+ * return result; })()
15469
+ * ```
14938
15470
  *
14939
- * The loop counter is always a raw number. For targets that wrap numeric
14940
- * values (e.g. interval-js wraps with `_IA.point()`), references to the
14941
- * loop index inside the body are wrapped via `target.number`.
15471
+ * GLSL: multi-Element comprehension is not trivially representable in
15472
+ * GLSL (no dynamic arrays, no push). A compile-time error is thrown.
15473
+ * TODO(E3-GLSL): support GLSL multi-Element via a pre-declared fixed-size
15474
+ * array or by unrolling when bounds are known at compile time.
15475
+ *
15476
+ * Known issue (imperative form): the IIFE generated by form (1) has no
15477
+ * `return` statement, so `Loop(body, Element(i, Range(lo, hi)))` compiled
15478
+ * to JS evaluates to `undefined` at runtime, while CE evaluation returns a
15479
+ * `List` of body values. See `test/compute-engine/a1-c1-compile-parity.test.ts`
15480
+ * ("Loop compiles in JS") for the verify-only test that locks in the
15481
+ * current behavior.
14942
15482
  */
14943
15483
  static compileForLoop(args, target) {
14944
15484
  if (!args[0]) throw new Error("Loop: no body");
14945
15485
  if (!args[1]) throw new Error("Loop: no indexing set");
14946
- const indexing = args[1];
15486
+ const body = args[0];
15487
+ const elements = args.slice(1);
15488
+ const useComprehension = elements.length > 1 || elements.length === 1 && isFunction2(elements[0], "Element") && !_BaseCompiler.isLegacyCompatibleRange(elements[0].ops[1]);
15489
+ if (useComprehension) {
15490
+ const lang = target.language ?? "";
15491
+ if (lang === "glsl" || lang === "wgsl") {
15492
+ throw new Error(
15493
+ `${lang.toUpperCase()}: multi-Element Loop comprehension is not yet supported. TODO(E3-GLSL): unroll or use a fixed-size array.`
15494
+ );
15495
+ }
15496
+ const narrowedElements = [];
15497
+ for (let i = 0; i < elements.length; i++) {
15498
+ const elem = elements[i];
15499
+ if (!isFunction2(elem, "Element"))
15500
+ throw new Error(
15501
+ `Loop: argument ${i + 1} must be an Element clause, got ${elem.operator ?? "?"}`
15502
+ );
15503
+ if (!isSymbol2(elem.ops[0]))
15504
+ throw new Error(
15505
+ `Loop: Element index (argument ${i + 1}) must be a symbol`
15506
+ );
15507
+ narrowedElements.push(elem);
15508
+ }
15509
+ const loopVarSet = new Set(
15510
+ narrowedElements.map(
15511
+ (e) => e.ops[0].symbol
15512
+ )
15513
+ );
15514
+ const needsWrap2 = target.number(0) !== "0";
15515
+ const bodyTarget2 = needsWrap2 ? {
15516
+ ...target,
15517
+ var: (id) => loopVarSet.has(id) ? target.number(0).replace("0", id) : target.var(id)
15518
+ } : target;
15519
+ const bodyCode = _BaseCompiler.compile(body, bodyTarget2);
15520
+ let inner = `result.push(${bodyCode});`;
15521
+ for (let i = narrowedElements.length - 1; i >= 0; i--) {
15522
+ const elem = narrowedElements[i];
15523
+ const name = elem.ops[0].symbol;
15524
+ const collExpr = elem.ops[1];
15525
+ let collection;
15526
+ if (isFunction2(collExpr, "Range")) {
15527
+ collection = _BaseCompiler.compileRangeIterable(collExpr, bodyTarget2);
15528
+ } else {
15529
+ collection = _BaseCompiler.compile(collExpr, bodyTarget2);
15530
+ }
15531
+ inner = `for (const ${name} of ${collection}) { ${inner} }`;
15532
+ }
15533
+ return `(() => { const result = []; ${inner} return result; })()`;
15534
+ }
15535
+ const indexing = elements[0];
14947
15536
  if (!isFunction2(indexing, "Element"))
14948
15537
  throw new Error("Loop: expected Element(index, Range(lo, hi))");
14949
15538
  const indexExpr = indexing.ops[0];
@@ -14961,13 +15550,72 @@ ${lines.join("\n")}`;
14961
15550
  ...target,
14962
15551
  var: (id) => id === index ? needsWrap ? target.number(0).replace("0", index) : index : target.var(id)
14963
15552
  };
14964
- const bodyStmts = _BaseCompiler.compileLoopBody(args[0], bodyTarget);
15553
+ const bodyStmts = _BaseCompiler.compileLoopBody(body, bodyTarget);
14965
15554
  return `(() => {${target.ws(
14966
15555
  "\n"
14967
15556
  )}for (let ${index} = ${lower}; ${index} <= ${upper}; ${index}++) {${target.ws(
14968
15557
  "\n"
14969
15558
  )}${bodyStmts}${target.ws("\n")}}${target.ws("\n")}})()`;
14970
15559
  }
15560
+ /**
15561
+ * Returns `true` when the given collection expression is a `Range` whose
15562
+ * runtime semantics match the legacy imperative for-loop shape
15563
+ * `for (let i = lo; i <= hi; i++)`.
15564
+ *
15565
+ * Concretely: integer-ascending bounds and step omitted-or-1. When bounds
15566
+ * are not statically numeric we accept the Range (the historical
15567
+ * behaviour) — runtime mismatch in the descending-unknown-bounds case is
15568
+ * left as a known limitation; callers can force the iterable path by
15569
+ * supplying an explicit step.
15570
+ */
15571
+ static isLegacyCompatibleRange(coll) {
15572
+ if (!isFunction2(coll, "Range")) return false;
15573
+ if (coll.ops.length >= 3) {
15574
+ const stepExpr = coll.ops[2];
15575
+ if (!isNumber(stepExpr) || stepExpr.re !== 1) return false;
15576
+ }
15577
+ const lo = coll.ops[0];
15578
+ const hi = coll.ops[1];
15579
+ if (isNumber(lo) && !Number.isInteger(lo.re)) return false;
15580
+ if (isNumber(hi) && !Number.isInteger(hi.re)) return false;
15581
+ if (isNumber(lo) && isNumber(hi) && lo.re > hi.re) return false;
15582
+ return true;
15583
+ }
15584
+ /**
15585
+ * Compile a `Range(lo, hi)` or `Range(lo, hi, step)` expression into a JS
15586
+ * iterable expression. Mirrors the runtime semantics in
15587
+ * `library/collections.ts` Range:
15588
+ * count = step === 0 ? 0 : max(0, floor((hi - lo) / step) + 1)
15589
+ * element = lo + step * k (0-indexed)
15590
+ * Default step is 1 when omitted. Bounds and step may be fractional.
15591
+ *
15592
+ * Only used from the comprehension path in `compileForLoop`.
15593
+ * Caller must have already verified `isFunction(rangeExpr, 'Range')`.
15594
+ */
15595
+ static compileRangeIterable(rangeExpr, target) {
15596
+ const loExpr = rangeExpr.ops[0];
15597
+ const hiExpr = rangeExpr.ops[1];
15598
+ const stepExpr = rangeExpr.ops[2];
15599
+ if (isNumber(loExpr) && isNumber(hiExpr) && (stepExpr === void 0 || isNumber(stepExpr))) {
15600
+ const lo2 = loExpr.re;
15601
+ const hi2 = hiExpr.re;
15602
+ const step2 = stepExpr === void 0 ? hi2 >= lo2 ? 1 : -1 : stepExpr.re;
15603
+ if (step2 === 0) return "[]";
15604
+ const len = Math.max(0, Math.floor((hi2 - lo2) / step2) + 1);
15605
+ if (step2 === 1) {
15606
+ if (lo2 === 0) return `Array.from({length:${len}},(_,k)=>k)`;
15607
+ return `Array.from({length:${len}},(_,k)=>${lo2}+k)`;
15608
+ }
15609
+ return `Array.from({length:${len}},(_,k)=>${lo2}+(${step2})*k)`;
15610
+ }
15611
+ const lo = _BaseCompiler.compile(loExpr, target);
15612
+ const hi = _BaseCompiler.compile(hiExpr, target);
15613
+ if (stepExpr === void 0) {
15614
+ 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})`;
15615
+ }
15616
+ const step = _BaseCompiler.compile(stepExpr, target);
15617
+ 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})`;
15618
+ }
14971
15619
  /**
14972
15620
  * Compile a loop body expression as statements (not wrapped in IIFE).
14973
15621
  * Handles Break, Continue, Return as statements, and If as if-else when
@@ -19918,6 +20566,7 @@ ${lines.join("\n")}`;
19918
20566
  return `_SYS.cexp(${compile2(args[0])})`;
19919
20567
  return `Math.exp(${compile2(args[0])})`;
19920
20568
  },
20569
+ First: (args, compile2) => `${compile2(args[0])}[0]`,
19921
20570
  Floor: (args, compile2) => {
19922
20571
  if (BaseCompiler.isIntegerValued(args[0])) return compile2(args[0]);
19923
20572
  return `Math.floor(${compile2(args[0])})`;
@@ -20076,7 +20725,20 @@ ${lines.join("\n")}`;
20076
20725
  if (nConst !== void 0) return `Math.pow(${compile2(arg)}, ${1 / nConst})`;
20077
20726
  return `Math.pow(${compile2(arg)}, 1 / (${compile2(exp3)}))`;
20078
20727
  },
20079
- Random: "Math.random",
20728
+ Random: (args, compile2) => {
20729
+ if (args.length === 0) return "Math.random()";
20730
+ if (args.length === 2) {
20731
+ const m = compile2(args[0]);
20732
+ const n = compile2(args[1]);
20733
+ return `((${m}) + Math.floor(Math.random() * ((${n}) - (${m}))))`;
20734
+ }
20735
+ const arg = args[0];
20736
+ if (BaseCompiler.isIntegerValued(arg)) {
20737
+ return `Math.floor(Math.random() * (${compile2(arg)}))`;
20738
+ }
20739
+ const a = compile2(arg);
20740
+ return `(() => { const _s = (${a}) * 12.9898; const _v = Math.sin(_s) * 43758.5453; return _v - Math.floor(_v); })()`;
20741
+ },
20080
20742
  Round: (args, compile2) => {
20081
20743
  if (BaseCompiler.isIntegerValued(args[0])) return compile2(args[0]);
20082
20744
  return `Math.round(${compile2(args[0])})`;
@@ -20104,6 +20766,7 @@ ${lines.join("\n")}`;
20104
20766
  if (BaseCompiler.isComplexValued(arg)) return `_SYS.csech(${compile2(arg)})`;
20105
20767
  return `1 / Math.cosh(${compile2(arg)})`;
20106
20768
  },
20769
+ Second: (args, compile2) => `${compile2(args[0])}[1]`,
20107
20770
  Heaviside: "_SYS.heaviside",
20108
20771
  Sign: "Math.sign",
20109
20772
  Sinc: "_SYS.sinc",
@@ -20136,6 +20799,7 @@ ${lines.join("\n")}`;
20136
20799
  return `_SYS.ctanh(${compile2(args[0])})`;
20137
20800
  return `Math.tanh(${compile2(args[0])})`;
20138
20801
  },
20802
+ Third: (args, compile2) => `${compile2(args[0])}[2]`,
20139
20803
  Mod: ([a, b], compile2) => {
20140
20804
  if (a === null || b === null) throw new Error("Mod: missing argument");
20141
20805
  const ca = compile2(a);
@@ -21415,6 +22079,14 @@ ${lines.join("\n")}`;
21415
22079
  return `exp(${compile2(args[0])})`;
21416
22080
  },
21417
22081
  Exp2: "exp2",
22082
+ // Component access — assumes the argument compiles to a vec2/vec3/vec4
22083
+ // (the common case for 2D/3D points). For 5+-element tuples that compile
22084
+ // to `float[N]` arrays, swizzle access is invalid GLSL and the shader
22085
+ // will fail to compile; that's an edge case `First`/`Second`/`Third`
22086
+ // aren't designed for. Vec swizzles are identical between GLSL and WGSL.
22087
+ First: (args, compile2) => `${compile2(args[0])}.x`,
22088
+ Second: (args, compile2) => `${compile2(args[0])}.y`,
22089
+ Third: (args, compile2) => `${compile2(args[0])}.z`,
21418
22090
  Floor: (args, compile2) => {
21419
22091
  if (BaseCompiler.isIntegerValued(args[0])) return compile2(args[0]);
21420
22092
  return `floor(${compile2(args[0])})`;
@@ -21892,6 +22564,39 @@ ${lines.join("\n")}`;
21892
22564
  // Sum/Product — unrolled or for-loop
21893
22565
  Sum: (args, compile2, target) => compileGPUSumProduct("Sum", args, compile2, target),
21894
22566
  Product: (args, compile2, target) => compileGPUSumProduct("Product", args, compile2, target),
22567
+ // Range — inline constant array literal (bounds must be compile-time constants)
22568
+ Range: (args, _compile, target) => {
22569
+ if (args.length < 2 || args.length > 3) {
22570
+ throw new Error(
22571
+ "Range: GPU compile expects 2 or 3 arguments (lo, hi, step?)"
22572
+ );
22573
+ }
22574
+ const lo = args[0].re;
22575
+ const hi = args[1].re;
22576
+ const step = args.length === 3 ? args[2].re : 1;
22577
+ if (!Number.isFinite(lo) || !Number.isFinite(hi) || !Number.isFinite(step)) {
22578
+ throw new Error(
22579
+ "Range: GPU compile requires constant numeric bounds (non-constant ranges must be materialized at JS host then uploaded as a uniform)"
22580
+ );
22581
+ }
22582
+ if (step === 0) throw new Error("Range: step cannot be zero");
22583
+ const count = Math.max(0, Math.floor((hi - lo) / step) + 1);
22584
+ if (count === 0) {
22585
+ throw new Error(
22586
+ "Range: empty range (lo > hi for positive step, or lo < hi for negative step)"
22587
+ );
22588
+ }
22589
+ if (count > 256) {
22590
+ throw new Error(
22591
+ `Range: GPU compile inlines ranges up to 256 elements (got ${count})`
22592
+ );
22593
+ }
22594
+ const values = [];
22595
+ for (let i = 0; i < count; i++) values.push(lo + i * step);
22596
+ const isWGSL = target.language === "wgsl";
22597
+ const arrayType = isWGSL ? `array<f32, ${count}>` : `float[${count}]`;
22598
+ return `${arrayType}(${values.map(formatGPUNumber).join(", ")})`;
22599
+ },
21895
22600
  // Loop — GPU for-loop (no IIFE, no let)
21896
22601
  Loop: (args, _compile, target) => {
21897
22602
  if (!args[0]) throw new Error("Loop: no body");
@@ -21920,6 +22625,134 @@ ${lines.join("\n")}`;
21920
22625
  ${bodyCode};
21921
22626
  }`;
21922
22627
  },
22628
+ // Statistical functions
22629
+ /**
22630
+ * GCD of two scalar arguments.
22631
+ *
22632
+ * Uses a preamble helper `_gpu_gcd` (Euclidean algorithm via `mod`).
22633
+ * Only two-argument form is supported in GPU targets.
22634
+ */
22635
+ GCD: (args, compile2) => {
22636
+ if (args.length < 2) throw new Error("GCD: need at least two arguments");
22637
+ if (args.length > 2)
22638
+ throw new Error("GCD: GPU target supports only two-argument GCD");
22639
+ const a = args[0];
22640
+ const b = args[1];
22641
+ if (a === null || b === null) throw new Error("GCD: missing argument");
22642
+ return `_gpu_gcd(${compile2(a)}, ${compile2(b)})`;
22643
+ },
22644
+ /**
22645
+ * Variance of a compile-time-known list.
22646
+ *
22647
+ * Accepts either a single `List(...)` argument or N scalar arguments.
22648
+ * Generates fully inline code: computes mean then sum of squared deviations,
22649
+ * divided by (N-1) for sample variance (matches JS `_SYS.variance`).
22650
+ */
22651
+ Variance: (args, compile2) => {
22652
+ let elems;
22653
+ if (args.length === 1 && isFunction2(args[0], "List")) {
22654
+ elems = args[0].ops;
22655
+ } else if (args.length >= 2) {
22656
+ elems = args;
22657
+ } else {
22658
+ throw new Error(
22659
+ "Variance: GPU target requires a List argument or at least 2 scalar arguments"
22660
+ );
22661
+ }
22662
+ const n = elems.length;
22663
+ if (n < 2) throw new Error("Variance: need at least 2 elements");
22664
+ const compiled = elems.map((e) => compile2(e));
22665
+ const sum = compiled.join(" + ");
22666
+ const mean2 = `((${sum}) / ${formatGPUNumber(n)})`;
22667
+ const sqDiffs = compiled.map((c) => `(${c} - ${mean2}) * (${c} - ${mean2})`).join(" + ");
22668
+ return `((${sqDiffs}) / ${formatGPUNumber(n - 1)})`;
22669
+ },
22670
+ /**
22671
+ * Median of a compile-time-known list.
22672
+ *
22673
+ * Accepts either a single `List(...)` argument or N scalar arguments.
22674
+ * For N ≤ 8: generates a fully unrolled inline sorting network followed by
22675
+ * a middle-element pick. For larger N, throws (too large to inline cleanly).
22676
+ *
22677
+ * The sorting network uses the "odd-even merge sort" comparator pattern
22678
+ * inlined as `min`/`max` calls — no GPU statements required.
22679
+ */
22680
+ Median: (args, compile2) => {
22681
+ let elems;
22682
+ if (args.length === 1 && isFunction2(args[0], "List")) {
22683
+ elems = args[0].ops;
22684
+ } else if (args.length >= 1) {
22685
+ elems = args;
22686
+ } else {
22687
+ throw new Error(
22688
+ "Median: GPU target requires a List argument or at least 1 scalar argument"
22689
+ );
22690
+ }
22691
+ const n = elems.length;
22692
+ if (n === 0) throw new Error("Median: empty list");
22693
+ if (n > 8) {
22694
+ throw new Error(
22695
+ `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.`
22696
+ );
22697
+ }
22698
+ const compiled = elems.map((e) => compile2(e));
22699
+ if (n === 1) return compiled[0];
22700
+ return `_gpu_median_${n}(${compiled.join(", ")})`;
22701
+ },
22702
+ /**
22703
+ * Deterministic pseudorandom for GPU.
22704
+ *
22705
+ * All emitted forms return a GLSL `float` (or WGSL `f32`) so the result
22706
+ * composes with surrounding float arithmetic without explicit casts. The
22707
+ * "integer-bound" forms return an integer-valued float (the result of
22708
+ * `floor`), matching the convention used by `Floor` and other ostensibly
22709
+ * integer-returning operators in this target.
22710
+ *
22711
+ * - 0 args (GLSL only): fall back to a fragment-coord-derived seed.
22712
+ * Only meaningful in fragment shaders (gl_FragCoord is FS-only).
22713
+ * - 0 args (WGSL): throws — WGSL has no built-in fragment coordinate;
22714
+ * caller must provide an explicit seed.
22715
+ * - 1 arg, real-typed: `_gpu_random(seed)` — deterministic float in [0, 1)
22716
+ * - 1 arg, integer-typed: `floor(_gpu_random(float(n)) * float(n))` —
22717
+ * integer-valued float in {0, 1, ..., n-1}. The seed is derived from
22718
+ * `n` itself, so the result is per-pixel-and-n deterministic in GLSL.
22719
+ * - 2 args (integer m, n): float in [m, n), seeded from gl_FragCoord.
22720
+ *
22721
+ * JS-side `Random` has matching semantics (see `library/core.ts`'s
22722
+ * polymorphic dispatch). JS↔GLSL parity is approximate — same seed yields
22723
+ * a similar value, not bit-identical, due to fp64 vs fp32 and platform
22724
+ * `sin` differences.
22725
+ */
22726
+ Random: (args, compile2, target) => {
22727
+ if (args.length === 0) {
22728
+ if (target.language === "wgsl") {
22729
+ throw new Error(
22730
+ "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."
22731
+ );
22732
+ }
22733
+ return "_gpu_random(gl_FragCoord.x + gl_FragCoord.y * 1024.0)";
22734
+ }
22735
+ if (args.length === 1) {
22736
+ const arg = args[0];
22737
+ if (BaseCompiler.isIntegerValued(arg)) {
22738
+ const compiled = compile2(arg);
22739
+ return `floor(_gpu_random(float(${compiled})) * float(${compiled}))`;
22740
+ }
22741
+ return `_gpu_random(${compile2(arg)})`;
22742
+ }
22743
+ if (args.length === 2) {
22744
+ if (target.language === "wgsl") {
22745
+ throw new Error(
22746
+ "Random(m, n): WGSL compile requires explicit seeding. Use a seeded variant or compute the integer range manually."
22747
+ );
22748
+ }
22749
+ const m = compile2(args[0]);
22750
+ const n = compile2(args[1]);
22751
+ const seed = "_gpu_random(gl_FragCoord.x + gl_FragCoord.y * 1024.0)";
22752
+ return `(float(${m}) + floor(${seed} * float((${n}) - (${m}))))`;
22753
+ }
22754
+ throw new Error("Random: GPU compile expects 0, 1, or 2 arguments");
22755
+ },
21923
22756
  // Function (lambda) — not supported in GPU
21924
22757
  Function: () => {
21925
22758
  throw new Error(
@@ -22518,6 +23351,212 @@ fn _fractal_julia(z_in: vec2f, c: vec2f, maxIter: i32) -> f32 {
22518
23351
  }
22519
23352
  return 1.0;
22520
23353
  }
23354
+ `;
23355
+ var GPU_GCD_PREAMBLE_GLSL = `
23356
+ float _gpu_gcd(float a, float b) {
23357
+ a = abs(a); b = abs(b);
23358
+ for (int i = 0; i < 32; i++) {
23359
+ if (b < 0.5) break;
23360
+ float t = mod(a, b);
23361
+ a = b;
23362
+ b = t;
23363
+ }
23364
+ return a;
23365
+ }
23366
+ `;
23367
+ var GPU_GCD_PREAMBLE_WGSL = `
23368
+ fn _gpu_gcd(a_in: f32, b_in: f32) -> f32 {
23369
+ var a = abs(a_in); var b = abs(b_in);
23370
+ for (var i: i32 = 0; i < 32; i++) {
23371
+ if (b < 0.5) { break; }
23372
+ let t = a % b;
23373
+ a = b;
23374
+ b = t;
23375
+ }
23376
+ return a;
23377
+ }
23378
+ `;
23379
+ var GPU_RANDOM_PREAMBLE_GLSL = `
23380
+ // Deterministic pseudorandom in [0, 1) from a float seed.
23381
+ // Standard fract-sin hash; reproducible across runs for the same seed.
23382
+ // Note: this hash exhibits visible banding near seed \u2248 k\u03C0 for integer k.
23383
+ // For high-quality shader random, callers should use a more robust hash
23384
+ // (e.g. PCG or xxHash) and pre-seed it appropriately.
23385
+ float _gpu_random(float seed) {
23386
+ return fract(sin(seed * 12.9898) * 43758.5453);
23387
+ }
23388
+ `;
23389
+ var GPU_RANDOM_PREAMBLE_WGSL = `
23390
+ // Deterministic pseudorandom in [0, 1) from a float seed.
23391
+ // Standard fract-sin hash; reproducible across runs for the same seed.
23392
+ // Note: this hash exhibits visible banding near seed \u2248 k\u03C0 for integer k.
23393
+ // For high-quality shader random, callers should use a more robust hash
23394
+ // (e.g. PCG or xxHash) and pre-seed it appropriately.
23395
+ fn _gpu_random(seed: f32) -> f32 {
23396
+ return fract(sin(seed * 12.9898) * 43758.5453);
23397
+ }
23398
+ `;
23399
+ var GPU_MEDIAN_PREAMBLE_GLSL = `
23400
+ float _gpu_median_2(float a, float b) {
23401
+ return (a + b) * 0.5;
23402
+ }
23403
+ float _gpu_median_3(float a, float b, float c) {
23404
+ return max(min(a, b), min(max(a, b), c));
23405
+ }
23406
+ float _gpu_median_4(float a, float b, float c, float d) {
23407
+ float lo = max(min(a, b), min(c, d));
23408
+ float hi = min(max(a, b), max(c, d));
23409
+ return (lo + hi) * 0.5;
23410
+ }
23411
+ float _gpu_median_5(float a, float b, float c, float d, float e) {
23412
+ // 9-comparator Bose-Nelson sort; v2 holds the median.
23413
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e;
23414
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
23415
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23416
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
23417
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
23418
+ t=min(v0,v3); v3=max(v0,v3); v0=t;
23419
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
23420
+ t=min(v1,v4); v4=max(v1,v4); v1=t;
23421
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
23422
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
23423
+ return v2;
23424
+ }
23425
+ float _gpu_median_6(float a, float b, float c, float d, float e, float f) {
23426
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f;
23427
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
23428
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
23429
+ t=min(v4,v5); v5=max(v4,v5); v4=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(v0,v4); v4=max(v0,v4); v0=t;
23433
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
23434
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
23435
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
23436
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
23437
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23438
+ return (v2 + v3) * 0.5;
23439
+ }
23440
+ float _gpu_median_7(float a, float b, float c, float d, float e, float f, float g) {
23441
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f,v6=g;
23442
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
23443
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
23444
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
23445
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
23446
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
23447
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
23448
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
23449
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
23450
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
23451
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
23452
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
23453
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
23454
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23455
+ return v3;
23456
+ }
23457
+ float _gpu_median_8(float a, float b, float c, float d, float e, float f, float g, float h) {
23458
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f,v6=g,v7=h;
23459
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
23460
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
23461
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
23462
+ t=min(v6,v7); v7=max(v6,v7); v6=t;
23463
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
23464
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
23465
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
23466
+ t=min(v5,v7); v7=max(v5,v7); v5=t;
23467
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
23468
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
23469
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
23470
+ t=min(v3,v7); v7=max(v3,v7); v3=t;
23471
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
23472
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23473
+ t=min(v5,v6); v6=max(v5,v6); v5=t;
23474
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
23475
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
23476
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23477
+ return (v3 + v4) * 0.5;
23478
+ }
23479
+ `;
23480
+ var GPU_MEDIAN_PREAMBLE_WGSL = `
23481
+ fn _gpu_median_2(a: f32, b: f32) -> f32 {
23482
+ return (a + b) * 0.5;
23483
+ }
23484
+ fn _gpu_median_3(a: f32, b: f32, c: f32) -> f32 {
23485
+ return max(min(a, b), min(max(a, b), c));
23486
+ }
23487
+ fn _gpu_median_4(a: f32, b: f32, c: f32, d: f32) -> f32 {
23488
+ let lo = max(min(a, b), min(c, d));
23489
+ let hi = min(max(a, b), max(c, d));
23490
+ return (lo + hi) * 0.5;
23491
+ }
23492
+ fn _gpu_median_5(a: f32, b: f32, c: f32, d: f32, e: f32) -> f32 {
23493
+ // 9-comparator Bose-Nelson sort; v2 holds the median.
23494
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var t: f32;
23495
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
23496
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23497
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
23498
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
23499
+ t=min(v0,v3); v3=max(v0,v3); v0=t;
23500
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
23501
+ t=min(v1,v4); v4=max(v1,v4); v1=t;
23502
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
23503
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
23504
+ return v2;
23505
+ }
23506
+ fn _gpu_median_6(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) -> f32 {
23507
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var v5=f; var t: f32;
23508
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
23509
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
23510
+ t=min(v4,v5); v5=max(v4,v5); v4=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(v0,v4); v4=max(v0,v4); v0=t;
23514
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
23515
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
23516
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
23517
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
23518
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23519
+ return (v2 + v3) * 0.5;
23520
+ }
23521
+ fn _gpu_median_7(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32, g: f32) -> f32 {
23522
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var v5=f; var v6=g; var t: f32;
23523
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
23524
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
23525
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
23526
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
23527
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
23528
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
23529
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
23530
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
23531
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
23532
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
23533
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
23534
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
23535
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23536
+ return v3;
23537
+ }
23538
+ fn _gpu_median_8(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32, g: f32, h: f32) -> f32 {
23539
+ 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;
23540
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
23541
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
23542
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
23543
+ t=min(v6,v7); v7=max(v6,v7); v6=t;
23544
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
23545
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
23546
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
23547
+ t=min(v5,v7); v7=max(v5,v7); v5=t;
23548
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
23549
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
23550
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
23551
+ t=min(v3,v7); v7=max(v3,v7); v3=t;
23552
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
23553
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23554
+ t=min(v5,v6); v6=max(v5,v6); v5=t;
23555
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
23556
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
23557
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
23558
+ return (v3 + v4) * 0.5;
23559
+ }
22521
23560
  `;
22522
23561
  var GPU_COLOR_PREAMBLE_GLSL = `
22523
23562
  float _gpu_srgb_to_linear(float c) {
@@ -23196,6 +24235,12 @@ fn _gpu_apca(lch_bg: vec3f, lch_fg: vec3f) -> f32 {
23196
24235
  if (code.includes("_fractal_")) {
23197
24236
  preamble += this.languageId === "wgsl" ? GPU_FRACTAL_PREAMBLE_WGSL : GPU_FRACTAL_PREAMBLE_GLSL;
23198
24237
  }
24238
+ if (code.includes("_gpu_random"))
24239
+ preamble += this.languageId === "wgsl" ? GPU_RANDOM_PREAMBLE_WGSL : GPU_RANDOM_PREAMBLE_GLSL;
24240
+ if (code.includes("_gpu_gcd"))
24241
+ preamble += this.languageId === "wgsl" ? GPU_GCD_PREAMBLE_WGSL : GPU_GCD_PREAMBLE_GLSL;
24242
+ if (code.includes("_gpu_median_"))
24243
+ preamble += this.languageId === "wgsl" ? GPU_MEDIAN_PREAMBLE_WGSL : GPU_MEDIAN_PREAMBLE_GLSL;
23199
24244
  if (code.includes("_gpu_srgb_to") || code.includes("_gpu_oklab") || code.includes("_gpu_oklch") || code.includes("_gpu_color_mix") || code.includes("_gpu_apca")) {
23200
24245
  preamble += this.languageId === "wgsl" ? GPU_COLOR_PREAMBLE_WGSL : GPU_COLOR_PREAMBLE_GLSL;
23201
24246
  }
@@ -25534,7 +26579,7 @@ ${code}`;
25534
26579
  }
25535
26580
 
25536
26581
  // src/compile.ts
25537
- var version = "0.56.0";
26582
+ var version = "0.58.0";
25538
26583
  return __toCommonJS(compile_exports);
25539
26584
  })();
25540
26585
  /*! Bundled license information: