@cortex-js/compute-engine 0.57.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 +690 -53
  2. package/dist/compile.min.esm.js +251 -51
  3. package/dist/compile.min.umd.cjs +251 -51
  4. package/dist/compile.umd.cjs +690 -53
  5. package/dist/compute-engine.esm.js +1079 -132
  6. package/dist/compute-engine.min.esm.js +271 -71
  7. package/dist/compute-engine.min.umd.cjs +270 -70
  8. package/dist/compute-engine.umd.cjs +1079 -132
  9. package/dist/core.esm.js +1078 -131
  10. package/dist/core.min.esm.js +269 -69
  11. package/dist/core.min.umd.cjs +269 -69
  12. package/dist/core.umd.cjs +1078 -131
  13. package/dist/interval.esm.js +132 -15
  14. package/dist/interval.min.esm.js +6 -6
  15. package/dist/interval.min.umd.cjs +6 -6
  16. package/dist/interval.umd.cjs +132 -15
  17. package/dist/latex-syntax.esm.js +132 -15
  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 +132 -15
  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 +3 -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 +8 -1
  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 +17 -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 +1 -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 +1 -1
  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 +34 -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
package/dist/core.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- /** Compute Engine 0.57.0 */
1
+ /** Compute Engine 0.58.0 */
2
2
 
3
3
  // node_modules/complex-esm/dist/src/complex.js
4
4
  var cosh = Math.cosh || function(x) {
@@ -4268,7 +4268,42 @@ function widen2(a, b) {
4268
4268
  if (b === "nothing") return a;
4269
4269
  if (isSubtype(a, b)) return b;
4270
4270
  if (isSubtype(b, a)) return a;
4271
- return superType(a, b);
4271
+ const sup = superType(a, b);
4272
+ if (LOSSY_SUPERTYPE.has(sup)) return unionTypes(a, b);
4273
+ return sup;
4274
+ }
4275
+ var LOSSY_SUPERTYPE = /* @__PURE__ */ new Set([
4276
+ "scalar",
4277
+ "value",
4278
+ "function",
4279
+ "expression",
4280
+ "collection",
4281
+ "indexed_collection",
4282
+ "list",
4283
+ "set",
4284
+ "tuple",
4285
+ "record",
4286
+ "dictionary",
4287
+ "map",
4288
+ "any"
4289
+ ]);
4290
+ function unionTypes(a, b) {
4291
+ const members = [];
4292
+ const push = (t) => {
4293
+ if (typeof t === "object" && t.kind === "union") {
4294
+ for (const m of t.types) push(m);
4295
+ return;
4296
+ }
4297
+ const key = typeof t === "string" ? t : JSON.stringify(t);
4298
+ if (!members.some(
4299
+ (m) => (typeof m === "string" ? m : JSON.stringify(m)) === key
4300
+ ))
4301
+ members.push(t);
4302
+ };
4303
+ push(a);
4304
+ push(b);
4305
+ if (members.length === 1) return members[0];
4306
+ return { kind: "union", types: members };
4272
4307
  }
4273
4308
  function narrow(...types) {
4274
4309
  if (types.length === 0) return "nothing";
@@ -4346,7 +4381,7 @@ function collectionElementType(type2) {
4346
4381
  if (type2.kind === "set") return type2.elements;
4347
4382
  if (type2.kind === "tuple") return widen(...type2.elements.map((x) => x.type));
4348
4383
  if (type2.kind === "dictionary")
4349
- return parseType(`tuple<string, ${type2.values}>`);
4384
+ return parseType(`tuple<string, ${typeToString(type2.values)}>`);
4350
4385
  if (type2.kind === "record") {
4351
4386
  return parseType(
4352
4387
  `tuple<string, ${typeToString(widen(...Object.values(type2.elements)))}>`
@@ -5892,6 +5927,84 @@ function sym(expr2) {
5892
5927
  }
5893
5928
 
5894
5929
  // src/compute-engine/boxed-expression/inequality-bounds.ts
5930
+ function extractIntervalBounds(expr2, symbol2) {
5931
+ if (isFunction2(expr2, "When")) {
5932
+ const cond = expr2.op2;
5933
+ if (!cond) return void 0;
5934
+ return extractIntervalBounds(cond, symbol2);
5935
+ }
5936
+ if (isFunction2(expr2, "Multiply")) {
5937
+ const ops = expr2.ops;
5938
+ if (!ops) return void 0;
5939
+ const merged = {};
5940
+ for (const sub2 of ops) {
5941
+ if (isFunction2(sub2, "When")) {
5942
+ const sub_ = extractIntervalBounds(sub2, symbol2);
5943
+ if (sub_ !== void 0) _mergeBounds(merged, sub_);
5944
+ }
5945
+ }
5946
+ return _hasAnyBound(merged) ? merged : void 0;
5947
+ }
5948
+ const result = {};
5949
+ if (isFunction2(expr2, "And")) {
5950
+ const ops = expr2.ops;
5951
+ if (!ops) return void 0;
5952
+ for (const sub2 of ops) {
5953
+ const subBounds = extractIntervalBounds(sub2, symbol2);
5954
+ if (subBounds === void 0) continue;
5955
+ _mergeBounds(result, subBounds);
5956
+ }
5957
+ return _hasAnyBound(result) ? result : void 0;
5958
+ }
5959
+ const op = expr2.operator;
5960
+ if ((op === "Less" || op === "LessEqual" || op === "Greater" || op === "GreaterEqual") && isFunction2(expr2)) {
5961
+ const isStrict = op === "Less" || op === "Greater";
5962
+ const ops = expr2.ops;
5963
+ if (!ops || ops.length < 2) return void 0;
5964
+ const flipped = op === "Greater" || op === "GreaterEqual" ? [...ops].reverse() : ops;
5965
+ for (let i = 0; i < flipped.length; i++) {
5966
+ if (isSymbol2(flipped[i], symbol2)) {
5967
+ if (i > 0) {
5968
+ const candidate = flipped[i - 1];
5969
+ if (result.lower === void 0 || candidate.isGreater(result.lower) === true) {
5970
+ result.lower = candidate;
5971
+ result.lowerStrict = isStrict;
5972
+ }
5973
+ }
5974
+ if (i < flipped.length - 1) {
5975
+ const candidate = flipped[i + 1];
5976
+ if (result.upper === void 0 || candidate.isLess(result.upper) === true) {
5977
+ result.upper = candidate;
5978
+ result.upperStrict = isStrict;
5979
+ }
5980
+ }
5981
+ }
5982
+ }
5983
+ return _hasAnyBound(result) ? result : void 0;
5984
+ }
5985
+ return void 0;
5986
+ }
5987
+ function _mergeBounds(into, from) {
5988
+ if (from.lower !== void 0) {
5989
+ if (into.lower === void 0 || from.lower.isGreater(into.lower) === true) {
5990
+ into.lower = from.lower;
5991
+ into.lowerStrict = from.lowerStrict;
5992
+ } else if (from.lower.isSame(into.lower)) {
5993
+ into.lowerStrict = into.lowerStrict || from.lowerStrict;
5994
+ }
5995
+ }
5996
+ if (from.upper !== void 0) {
5997
+ if (into.upper === void 0 || from.upper.isLess(into.upper) === true) {
5998
+ into.upper = from.upper;
5999
+ into.upperStrict = from.upperStrict;
6000
+ } else if (from.upper.isSame(into.upper)) {
6001
+ into.upperStrict = into.upperStrict || from.upperStrict;
6002
+ }
6003
+ }
6004
+ }
6005
+ function _hasAnyBound(b) {
6006
+ return b.lower !== void 0 || b.upper !== void 0;
6007
+ }
5895
6008
  function getInequalityBoundsFromAssumptions(ce, symbol2) {
5896
6009
  const result = {};
5897
6010
  const assumptions = ce.context?.assumptions;
@@ -5908,8 +6021,8 @@ function getInequalityBoundsFromAssumptions(ce, symbol2) {
5908
6021
  const isStrict = op === "Less";
5909
6022
  if (isFunction2(lhs, "Negate") && isSymbol2(lhs.op1, symbol2)) {
5910
6023
  const bound = ce.Zero;
5911
- if (result.lowerBound === void 0 || bound.isGreater(result.lowerBound) === true) {
5912
- result.lowerBound = bound;
6024
+ if (result.lower === void 0 || bound.isGreater(result.lower) === true) {
6025
+ result.lower = bound;
5913
6026
  result.lowerStrict = isStrict;
5914
6027
  }
5915
6028
  }
@@ -5928,16 +6041,16 @@ function getInequalityBoundsFromAssumptions(ce, symbol2) {
5928
6041
  }
5929
6042
  if (hasNegatedSymbol && constantSum !== 0) {
5930
6043
  const bound = ce.expr(constantSum);
5931
- if (result.lowerBound === void 0 || bound.isGreater(result.lowerBound) === true) {
5932
- result.lowerBound = bound;
6044
+ if (result.lower === void 0 || bound.isGreater(result.lower) === true) {
6045
+ result.lower = bound;
5933
6046
  result.lowerStrict = isStrict;
5934
6047
  }
5935
6048
  }
5936
6049
  }
5937
6050
  if (isSymbol2(lhs, symbol2)) {
5938
6051
  const bound = ce.Zero;
5939
- if (result.upperBound === void 0 || bound.isLess(result.upperBound) === true) {
5940
- result.upperBound = bound;
6052
+ if (result.upper === void 0 || bound.isLess(result.upper) === true) {
6053
+ result.upper = bound;
5941
6054
  result.upperStrict = isStrict;
5942
6055
  }
5943
6056
  }
@@ -5956,8 +6069,8 @@ function getInequalityBoundsFromAssumptions(ce, symbol2) {
5956
6069
  }
5957
6070
  if (hasSymbol && constantSum !== 0) {
5958
6071
  const bound = ce.expr(-constantSum);
5959
- if (result.upperBound === void 0 || bound.isLess(result.upperBound) === true) {
5960
- result.upperBound = bound;
6072
+ if (result.upper === void 0 || bound.isLess(result.upper) === true) {
6073
+ result.upper = bound;
5961
6074
  result.upperStrict = isStrict;
5962
6075
  }
5963
6076
  }
@@ -6177,8 +6290,8 @@ function cmp(a, b) {
6177
6290
  const bounds = getInequalityBoundsFromAssumptions(a.engine, b.symbol);
6178
6291
  const aNum = typeof a.numericValue === "number" ? a.numericValue : a.numericValue.re;
6179
6292
  if (aNum !== void 0 && Number.isFinite(aNum)) {
6180
- if (bounds.lowerBound !== void 0) {
6181
- const lb = bounds.lowerBound;
6293
+ if (bounds.lower !== void 0) {
6294
+ const lb = bounds.lower;
6182
6295
  const lowerNum = isNumber(lb) ? typeof lb.numericValue === "number" ? lb.numericValue : lb.numericValue.re : void 0;
6183
6296
  if (lowerNum !== void 0 && Number.isFinite(lowerNum)) {
6184
6297
  if (lowerNum > aNum) return "<";
@@ -6186,8 +6299,8 @@ function cmp(a, b) {
6186
6299
  if (lowerNum === aNum && !bounds.lowerStrict) return "<=";
6187
6300
  }
6188
6301
  }
6189
- if (bounds.upperBound !== void 0) {
6190
- const ub = bounds.upperBound;
6302
+ if (bounds.upper !== void 0) {
6303
+ const ub = bounds.upper;
6191
6304
  const upperNum = isNumber(ub) ? typeof ub.numericValue === "number" ? ub.numericValue : ub.numericValue.re : void 0;
6192
6305
  if (upperNum !== void 0 && Number.isFinite(upperNum)) {
6193
6306
  if (upperNum < aNum) return ">";
@@ -6217,8 +6330,8 @@ function cmp(a, b) {
6217
6330
  if (typeof b === "number") {
6218
6331
  if (isSymbol2(a)) {
6219
6332
  const bounds = getInequalityBoundsFromAssumptions(a.engine, a.symbol);
6220
- if (bounds.lowerBound !== void 0) {
6221
- const lb = bounds.lowerBound;
6333
+ if (bounds.lower !== void 0) {
6334
+ const lb = bounds.lower;
6222
6335
  const lowerNum = isNumber(lb) ? typeof lb.numericValue === "number" ? lb.numericValue : lb.numericValue.re : void 0;
6223
6336
  if (lowerNum !== void 0 && Number.isFinite(lowerNum)) {
6224
6337
  if (lowerNum > b) return ">";
@@ -6226,8 +6339,8 @@ function cmp(a, b) {
6226
6339
  if (lowerNum === b && !bounds.lowerStrict) return ">=";
6227
6340
  }
6228
6341
  }
6229
- if (bounds.upperBound !== void 0) {
6230
- const ub = bounds.upperBound;
6342
+ if (bounds.upper !== void 0) {
6343
+ const ub = bounds.upper;
6231
6344
  const upperNum = isNumber(ub) ? typeof ub.numericValue === "number" ? ub.numericValue : ub.numericValue.re : void 0;
6232
6345
  if (upperNum !== void 0 && Number.isFinite(upperNum)) {
6233
6346
  if (upperNum < b) return "<";
@@ -6283,8 +6396,8 @@ function cmp(a, b) {
6283
6396
  const bounds = getInequalityBoundsFromAssumptions(a.engine, a.symbol);
6284
6397
  const bNum = typeof b.numericValue === "number" ? b.numericValue : b.numericValue.re;
6285
6398
  if (bNum !== void 0 && Number.isFinite(bNum)) {
6286
- if (bounds.lowerBound !== void 0) {
6287
- const lb = bounds.lowerBound;
6399
+ if (bounds.lower !== void 0) {
6400
+ const lb = bounds.lower;
6288
6401
  const lowerNum = isNumber(lb) ? typeof lb.numericValue === "number" ? lb.numericValue : lb.numericValue.re : void 0;
6289
6402
  if (lowerNum !== void 0 && Number.isFinite(lowerNum)) {
6290
6403
  if (lowerNum > bNum) return ">";
@@ -6292,8 +6405,8 @@ function cmp(a, b) {
6292
6405
  if (lowerNum === bNum && !bounds.lowerStrict) return ">=";
6293
6406
  }
6294
6407
  }
6295
- if (bounds.upperBound !== void 0) {
6296
- const ub = bounds.upperBound;
6408
+ if (bounds.upper !== void 0) {
6409
+ const ub = bounds.upper;
6297
6410
  const upperNum = isNumber(ub) ? typeof ub.numericValue === "number" ? ub.numericValue : ub.numericValue.re : void 0;
6298
6411
  if (upperNum !== void 0 && Number.isFinite(upperNum)) {
6299
6412
  if (upperNum < bNum) return "<";
@@ -6831,6 +6944,12 @@ var _BoxedOperatorDefinition = class {
6831
6944
  scoped = false;
6832
6945
  signature;
6833
6946
  inferredSignature = true;
6947
+ /** True if this operator definition was created from a user-defined
6948
+ * function literal (e.g. via `ce.assign('f', ce.parse('x \\mapsto x^2'))`).
6949
+ * Used to enable auto-broadcasting when applied to indexed collections.
6950
+ * @internal
6951
+ */
6952
+ _isLambda = false;
6834
6953
  type;
6835
6954
  sgn;
6836
6955
  eq;
@@ -6988,6 +7107,8 @@ var _BoxedOperatorDefinition = class {
6988
7107
  this.engine._typeResolver
6989
7108
  );
6990
7109
  }
7110
+ if (isFunction2(boxedFn) && boxedFn.operator === "Function")
7111
+ this._isLambda = true;
6991
7112
  const fn = applicable(boxedFn);
6992
7113
  evaluate2 = (xs, _options) => fn(xs);
6993
7114
  Object.defineProperty(evaluate2, "toString", {
@@ -8304,6 +8425,29 @@ var _BoxedExpression = class __BoxedExpression {
8304
8425
  get isReal() {
8305
8426
  return void 0;
8306
8427
  }
8428
+ toSignedFunction() {
8429
+ const op = this.operator;
8430
+ if (op === void 0 || this.ops === void 0 || this.ops.length < 2) {
8431
+ return void 0;
8432
+ }
8433
+ const [lhs, rhs] = this.ops;
8434
+ const engine = this.engine;
8435
+ switch (op) {
8436
+ case "Equal":
8437
+ case "NotEqual":
8438
+ case "Less":
8439
+ case "LessEqual":
8440
+ return engine.function("Subtract", [lhs, rhs]);
8441
+ case "Greater":
8442
+ case "GreaterEqual":
8443
+ return engine.function("Subtract", [rhs, lhs]);
8444
+ default:
8445
+ return void 0;
8446
+ }
8447
+ }
8448
+ getInterval(symbol2) {
8449
+ return extractIntervalBounds(this, symbol2);
8450
+ }
8307
8451
  simplify(_options) {
8308
8452
  return this;
8309
8453
  }
@@ -10322,15 +10466,16 @@ var DEFINITIONS_CORE = [
10322
10466
  precedence: ASSIGNMENT_PRECEDENCE,
10323
10467
  parse: parseAssign
10324
10468
  },
10325
- // General colon operator (type annotation, mapping notation)
10326
- // Precedence below assignment (260) so `:=` takes priority,
10327
- // and below arrows (270) so `f: A \to B` parses as `Colon(f, To(A, B))`
10469
+ // General colon operator (type annotation, mapping notation, Desmos piecewise)
10470
+ // Precedence below comparisons (245) so `cond : val` (Desmos compact piecewise)
10471
+ // parses as `Colon(cond, val)`, and below arrows (270) so
10472
+ // `f: A \to B` parses as `Colon(f, To(A, B))`.
10328
10473
  {
10329
10474
  name: "Colon",
10330
10475
  latexTrigger: ":",
10331
10476
  kind: "infix",
10332
10477
  associativity: "right",
10333
- precedence: 250,
10478
+ precedence: 240,
10334
10479
  serialize: (serializer, expr2) => joinLatex([
10335
10480
  serializer.serialize(operand(expr2, 1)),
10336
10481
  "\\colon",
@@ -10341,7 +10486,7 @@ var DEFINITIONS_CORE = [
10341
10486
  latexTrigger: "\\colon",
10342
10487
  kind: "infix",
10343
10488
  associativity: "right",
10344
- precedence: 250,
10489
+ precedence: 240,
10345
10490
  parse: "Colon"
10346
10491
  },
10347
10492
  {
@@ -11911,7 +12056,10 @@ function parseForComprehension(parser, lhs, until) {
11911
12056
  p.skipVisualSpace();
11912
12057
  const isComma = p.peek === ",";
11913
12058
  p.index = saved;
11914
- return isComma;
12059
+ if (isComma) return true;
12060
+ if (peekKeyword(p, "where")) return true;
12061
+ if (peekKeyword(p, "with")) return true;
12062
+ return false;
11915
12063
  }
11916
12064
  };
11917
12065
  const elements = [];
@@ -11952,6 +12100,25 @@ function parseWhereExpression(parser, lhs, until) {
11952
12100
  parser.skipVisualSpace();
11953
12101
  } while (parser.match(","));
11954
12102
  if (bindings.length === 0) return null;
12103
+ const forStart = parser.index;
12104
+ if (matchKeyword(parser, "for")) {
12105
+ const loop = parseForComprehension(parser, lhs, until);
12106
+ if (loop) {
12107
+ const block2 = [];
12108
+ for (const b of bindings) {
12109
+ const normalized = normalizeLocalAssign(b);
12110
+ if (operator(normalized) === "Assign") {
12111
+ block2.push(["Declare", operand(normalized, 1)]);
12112
+ block2.push(normalized);
12113
+ } else {
12114
+ block2.push(normalized);
12115
+ }
12116
+ }
12117
+ block2.push(loop);
12118
+ return ["Block", ...block2];
12119
+ }
12120
+ parser.index = forStart;
12121
+ }
11955
12122
  const block = [];
11956
12123
  for (const b of bindings) {
11957
12124
  const normalized = normalizeLocalAssign(b);
@@ -12165,6 +12332,17 @@ function parseIntervalBody(body, openLeft, openRight) {
12165
12332
  const upperExpr = openRight ? ["Open", upper] : upper;
12166
12333
  return ["Interval", lowerExpr, upperExpr];
12167
12334
  }
12335
+ var COMPARISON_HEADS = /* @__PURE__ */ new Set([
12336
+ "Less",
12337
+ "LessEqual",
12338
+ "Greater",
12339
+ "GreaterEqual",
12340
+ "Equal",
12341
+ "NotEqual",
12342
+ "And",
12343
+ "Or",
12344
+ "Not"
12345
+ ]);
12168
12346
  var DEFINITIONS_SETS = [
12169
12347
  //
12170
12348
  // Constants
@@ -12423,18 +12601,58 @@ var DEFINITIONS_SETS = [
12423
12601
  closeTrigger: "}",
12424
12602
  parse: (_parser, body) => {
12425
12603
  if (isEmptySequence(body)) return "EmptySet";
12604
+ if (operator(body) == "Delimiter" && stringValue(operand(body, 2)) === ",") {
12605
+ body = operand(body, 1);
12606
+ }
12426
12607
  const h = operator(body);
12427
- if (h === "Divides" || h === "Colon") {
12608
+ if (h === "Divides") {
12428
12609
  const expr2 = operand(body, 1);
12429
12610
  const condition = operand(body, 2);
12430
12611
  if (expr2 !== null && condition !== null)
12431
12612
  return ["Set", expr2, ["Condition", condition]];
12432
12613
  }
12433
- if (operator(body) == "Delimiter" && stringValue(operand(body, 2)) === ",") {
12434
- body = operand(body, 1);
12614
+ if (h === "Colon") {
12615
+ const lhs = operand(body, 1);
12616
+ const rhs = operand(body, 2);
12617
+ if (lhs !== null && rhs !== null) {
12618
+ const lhsOp = operator(lhs);
12619
+ if (lhsOp !== null && COMPARISON_HEADS.has(lhsOp)) {
12620
+ return ["Which", lhs, rhs];
12621
+ }
12622
+ return ["Set", lhs, ["Condition", rhs]];
12623
+ }
12624
+ }
12625
+ if (h === "Sequence") {
12626
+ const elements = operands(body);
12627
+ const colonElements = elements.filter((el) => operator(el) === "Colon");
12628
+ const allPiecewise = colonElements.length > 0 && colonElements.every((el) => {
12629
+ const lhs = operand(el, 1);
12630
+ const lhsOp = lhs !== null ? operator(lhs) : null;
12631
+ return lhsOp !== null && COMPARISON_HEADS.has(lhsOp);
12632
+ });
12633
+ if (allPiecewise) {
12634
+ const whichOps = [];
12635
+ for (let i = 0; i < elements.length; i++) {
12636
+ const el = elements[i];
12637
+ if (operator(el) === "Colon") {
12638
+ const cond = operand(el, 1);
12639
+ const val = operand(el, 2);
12640
+ if (cond === null || val === null) {
12641
+ return ["Set", ...elements];
12642
+ }
12643
+ whichOps.push(cond, val);
12644
+ } else {
12645
+ if (i !== elements.length - 1) {
12646
+ return ["Set", ...elements];
12647
+ }
12648
+ whichOps.push("True", el);
12649
+ }
12650
+ }
12651
+ return ["Which", ...whichOps];
12652
+ }
12653
+ return ["Set", ...elements];
12435
12654
  }
12436
- if (operator(body) !== "Sequence") return ["Set", body];
12437
- return ["Set", ...operands(body)];
12655
+ return ["Set", body];
12438
12656
  },
12439
12657
  serialize: (serializer, expr2) => {
12440
12658
  if (nops(expr2) === 2 && operator(operand(expr2, 2)) === "Condition") {
@@ -14438,7 +14656,8 @@ function parseTrig(op) {
14438
14656
  minPrec: MULTIPLICATION_PRECEDENCE,
14439
14657
  condition: (parser2) => trigCommands[parser2.peek] || (until?.condition?.(parser2) ?? false)
14440
14658
  });
14441
- const appliedFn = args === null ? fn : typeof fn === "string" ? [fn, ...args] : ["Apply", fn, ...args];
14659
+ const head = fn === "Arctan" && args?.length === 2 ? "Arctan2" : fn;
14660
+ const appliedFn = args === null ? fn : typeof head === "string" ? [head, ...args] : ["Apply", head, ...args];
14442
14661
  return sup === null ? appliedFn : ["Power", appliedFn, sup];
14443
14662
  };
14444
14663
  }
@@ -16654,10 +16873,17 @@ var DEFINITIONS_OTHERS = [
16654
16873
  // The capitalized library entries already exist; these are pure parse
16655
16874
  // aliases so the lowercase names don't land in `unsupported-operator`.
16656
16875
  // ---------------------------------------------------------------------------
16876
+ { latexTrigger: "\\operatorname{count}", parse: "Length" },
16657
16877
  { latexTrigger: "\\operatorname{random}", parse: "Random" },
16658
16878
  { latexTrigger: "\\operatorname{shuffle}", parse: "Shuffle" },
16659
16879
  { latexTrigger: "\\operatorname{repeat}", parse: "Repeat" },
16660
16880
  { latexTrigger: "\\operatorname{join}", parse: "Join" },
16881
+ { latexTrigger: "\\operatorname{range}", parse: "Range" },
16882
+ // Note: `\operatorname{with}` (Desmos's local-binding clause) is intentionally
16883
+ // NOT registered here. Use the math-notation equivalent `\operatorname{where}`
16884
+ // (with `\coloneq` for bindings), or register `with` as a custom dictionary
16885
+ // entry at the integration layer — see the "Desmos-Specific Syntax — Prefer
16886
+ // Custom LaTeX Dictionary" section in COMPUTE_ENGINE.md for a worked example.
16661
16887
  // ---------------------------------------------------------------------------
16662
16888
  // Geometric primitive heads. Registered as known typed heads so consumers
16663
16889
  // can branch on the operator name; CE itself doesn't render them. The
@@ -22499,6 +22725,15 @@ function expressionTensorInfo(operator2, rows) {
22499
22725
  }
22500
22726
  } else {
22501
22727
  for (const item of t) {
22728
+ const op = item.operator;
22729
+ if (op === "Tuple" || op === "Pair" || op === "Single" || op === "Triple" || op === "Quadruple" || op === "KeyValuePair" || op === "Dictionary" || op === "Set" || op === "Record") {
22730
+ valid = false;
22731
+ return;
22732
+ }
22733
+ if (item.type.type === "string") {
22734
+ valid = false;
22735
+ return;
22736
+ }
22502
22737
  dtype = getSupertype(dtype, getExpressionDatatype(item));
22503
22738
  }
22504
22739
  }
@@ -27534,6 +27769,15 @@ function interval(expr2) {
27534
27769
  return void 0;
27535
27770
  }
27536
27771
 
27772
+ // src/compute-engine/numerics/random.ts
27773
+ function deterministicRandom(seed) {
27774
+ const v = Math.sin(seed * 12.9898) * 43758.5453;
27775
+ return v - Math.floor(v);
27776
+ }
27777
+ function nextSeed(seed) {
27778
+ return seed + 0.6180339887498949;
27779
+ }
27780
+
27537
27781
  // src/compute-engine/boxed-expression/canonical-utils.ts
27538
27782
  function canonical(ce, xs, scope) {
27539
27783
  if (xs.every((x) => x.isCanonical)) return xs;
@@ -27583,6 +27827,19 @@ var COLLECTIONS_LIBRARY = {
27583
27827
  indexWhere: void 0
27584
27828
  }
27585
27829
  },
27830
+ Length: {
27831
+ description: "Number of elements in a collection. Returns undefined for non-collections and for infinite collections.",
27832
+ complexity: 4e3,
27833
+ signature: "(any) -> integer",
27834
+ type: () => "integer",
27835
+ evaluate: ([xs], { engine }) => {
27836
+ if (!xs.isCollection) return void 0;
27837
+ if (xs.isEmptyCollection) return engine.Zero;
27838
+ const n = xs.count;
27839
+ if (n === void 0 || !isFinite(n)) return void 0;
27840
+ return engine.number(n);
27841
+ }
27842
+ },
27586
27843
  Tuple: {
27587
27844
  description: "A fixed number of heterogeneous elements",
27588
27845
  complexity: 8200,
@@ -27836,10 +28093,12 @@ var COLLECTIONS_LIBRARY = {
27836
28093
  const upper = expr2.op2.re;
27837
28094
  let count = expr2.op3.re;
27838
28095
  if (!isFinite(count)) count = DEFAULT_LINSPACE_COUNT;
28096
+ count = Math.floor(count);
27839
28097
  if (!isFinite(lower) || !isFinite(upper)) return void 0;
27840
28098
  if (index < 1 || index > count) return void 0;
28099
+ if (count === 1) return expr2.engine.number(lower);
27841
28100
  return expr2.engine.number(
27842
- lower + (upper - lower) * (index - 1) / count
28101
+ lower + (upper - lower) * (index - 1) / (count - 1)
27843
28102
  );
27844
28103
  },
27845
28104
  iterator: (expr2) => {
@@ -27858,6 +28117,8 @@ var COLLECTIONS_LIBRARY = {
27858
28117
  !isFinite(expr2.op3.re) ? DEFAULT_LINSPACE_COUNT : expr2.op3.re
27859
28118
  );
27860
28119
  }
28120
+ totalCount = Math.floor(totalCount);
28121
+ const denom = totalCount > 1 ? totalCount - 1 : 1;
27861
28122
  let index = 1;
27862
28123
  return {
27863
28124
  next: () => {
@@ -27866,7 +28127,7 @@ var COLLECTIONS_LIBRARY = {
27866
28127
  index += 1;
27867
28128
  return {
27868
28129
  value: expr2.engine.number(
27869
- lower + (upper - lower) * (index - 1 - 1) / totalCount
28130
+ lower + (upper - lower) * (index - 1 - 1) / denom
27870
28131
  ),
27871
28132
  done: false
27872
28133
  };
@@ -27882,9 +28143,14 @@ var COLLECTIONS_LIBRARY = {
27882
28143
  if (t < lower || t > upper) return false;
27883
28144
  let count = expr2.op3.re;
27884
28145
  if (!isFinite(count)) count = DEFAULT_LINSPACE_COUNT;
28146
+ count = Math.floor(count);
27885
28147
  if (count === 0) return false;
27886
- const step = (upper - lower) / count;
27887
- return (t - lower) % step === 0;
28148
+ if (count === 1) return t === lower;
28149
+ const step = (upper - lower) / (count - 1);
28150
+ const k = (t - lower) / step;
28151
+ const tol = expr2.engine.tolerance;
28152
+ const kRounded = Math.round(k);
28153
+ return kRounded >= 0 && kRounded <= count - 1 && Math.abs(k - kRounded) < tol;
27888
28154
  }
27889
28155
  }
27890
28156
  },
@@ -28209,10 +28475,12 @@ var COLLECTIONS_LIBRARY = {
28209
28475
  description: [
28210
28476
  "Access an element of an indexed collection.",
28211
28477
  "If the index is negative, it is counted from the end.",
28212
- "Multiple indices can be provided to access nested collections (e.g., matrices)."
28478
+ "Multiple indices can be provided to access nested collections (e.g., matrices).",
28479
+ "If the index is a finite collection of booleans, returns the elements where the mask is True.",
28480
+ "If the index is a finite collection of integers, returns the elements at those indices."
28213
28481
  ],
28214
28482
  complexity: 8200,
28215
- signature: "(value: indexed_collection, index: (number|string)+) -> unknown",
28483
+ signature: "(value: indexed_collection, index: (number|string|indexed_collection)+) -> unknown",
28216
28484
  type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? collectionElementType(xs.type.type) ?? "any",
28217
28485
  evaluate: (ops, { engine: ce }) => {
28218
28486
  let expr2 = ops[0];
@@ -28223,12 +28491,39 @@ var COLLECTIONS_LIBRARY = {
28223
28491
  if (!at) return void 0;
28224
28492
  const opAtIndex = ops[index];
28225
28493
  const s = isString(opAtIndex) ? opAtIndex.string : void 0;
28226
- if (s !== void 0) expr2 = at(expr2, s) ?? ce.Nothing;
28227
- else {
28228
- const i = ops[index].re;
28229
- if (!Number.isInteger(i)) return void 0;
28230
- expr2 = at(expr2, i) ?? ce.Nothing;
28494
+ if (s !== void 0) {
28495
+ expr2 = at(expr2, s) ?? ce.Nothing;
28496
+ index += 1;
28497
+ continue;
28231
28498
  }
28499
+ if (opAtIndex.isCollection && opAtIndex.isFiniteCollection) {
28500
+ const indices = Array.from(opAtIndex.each());
28501
+ const isMask = indices.every((m) => {
28502
+ const name = sym(m);
28503
+ return name === "True" || name === "False";
28504
+ });
28505
+ const picked = [];
28506
+ if (isMask) {
28507
+ indices.forEach((m, i2) => {
28508
+ if (sym(m) !== "True") return;
28509
+ const v = at(expr2, i2 + 1);
28510
+ if (v !== void 0) picked.push(v);
28511
+ });
28512
+ } else {
28513
+ for (const m of indices) {
28514
+ const k = m.re;
28515
+ if (!Number.isInteger(k)) return void 0;
28516
+ const v = at(expr2, k);
28517
+ if (v !== void 0) picked.push(v);
28518
+ }
28519
+ }
28520
+ expr2 = ce._fn("List", picked);
28521
+ index += 1;
28522
+ continue;
28523
+ }
28524
+ const i = opAtIndex.re;
28525
+ if (!Number.isInteger(i)) return void 0;
28526
+ expr2 = at(expr2, i) ?? ce.Nothing;
28232
28527
  index += 1;
28233
28528
  }
28234
28529
  return expr2;
@@ -28239,7 +28534,7 @@ var COLLECTIONS_LIBRARY = {
28239
28534
  description: ["Return `n` elements from a collection."],
28240
28535
  complexity: 8200,
28241
28536
  signature: "(xs: indexed_collection, count: number) -> indexed_collection",
28242
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
28537
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
28243
28538
  evaluate: (ops, { engine, materialization: eager }) => {
28244
28539
  if (!eager) return void 0;
28245
28540
  const takeExpr = engine._fn("Take", ops);
@@ -28286,7 +28581,7 @@ var COLLECTIONS_LIBRARY = {
28286
28581
  description: ["Return the collection without the first n elements."],
28287
28582
  complexity: 8200,
28288
28583
  signature: "(xs: indexed_collection, count: number) -> indexed_collection",
28289
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
28584
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
28290
28585
  collection: {
28291
28586
  isLazy: (_expr) => true,
28292
28587
  count: (expr2) => {
@@ -28482,7 +28777,9 @@ var COLLECTIONS_LIBRARY = {
28482
28777
  ],
28483
28778
  complexity: 8200,
28484
28779
  signature: "(value: indexed_collection, start: number, end: number) -> list",
28485
- type: ([xs]) => parseType(`list<${collectionElementType(xs.type.type)}>`),
28780
+ type: ([xs]) => parseType(
28781
+ `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`
28782
+ ),
28486
28783
  collection: {
28487
28784
  isLazy: (_expr) => true,
28488
28785
  count: (expr2) => {
@@ -28814,16 +29111,26 @@ var COLLECTIONS_LIBRARY = {
28814
29111
  },
28815
29112
  // Randomize the order of the elements in the collection.
28816
29113
  Shuffle: {
28817
- description: "Randomize the order of the elements in the collection.",
29114
+ description: "Randomize the order of the elements in the collection. With an optional `seed` argument, the shuffle is deterministic.",
28818
29115
  complexity: 8200,
28819
- signature: "(indexed_collection) -> indexed_collection",
29116
+ signature: "(indexed_collection, real?) -> indexed_collection",
28820
29117
  type: (ops) => ops[0].type,
28821
- evaluate: ([xs], { engine: ce }) => {
29118
+ evaluate: ([xs, seedOp], { engine: ce }) => {
28822
29119
  if (!xs.isFiniteCollection) return void 0;
28823
29120
  const data = Array.from(xs.each());
28824
- for (let i = data.length - 1; i > 0; i--) {
28825
- const j = Math.floor(Math.random() * (i + 1));
28826
- [data[i], data[j]] = [data[j], data[i]];
29121
+ const seed = seedOp?.re;
29122
+ if (seed !== void 0 && !Number.isNaN(seed)) {
29123
+ let s = seed;
29124
+ for (let i = data.length - 1; i > 0; i--) {
29125
+ const j = Math.floor(deterministicRandom(s) * (i + 1));
29126
+ [data[i], data[j]] = [data[j], data[i]];
29127
+ s = nextSeed(s);
29128
+ }
29129
+ } else {
29130
+ for (let i = data.length - 1; i > 0; i--) {
29131
+ const j = Math.floor(Math.random() * (i + 1));
29132
+ [data[i], data[j]] = [data[j], data[i]];
29133
+ }
28827
29134
  }
28828
29135
  return ce.function(xs.operator, data);
28829
29136
  }
@@ -28890,7 +29197,9 @@ var COLLECTIONS_LIBRARY = {
28890
29197
  if (t === "string")
28891
29198
  return parseType(`tuple<list<string>, list<integer>>`);
28892
29199
  return parseType(
28893
- `tuple<list<${collectionElementType(t)}>, list<integer>>`
29200
+ `tuple<list<${typeToString(
29201
+ collectionElementType(t) ?? "any"
29202
+ )}>, list<integer>>`
28894
29203
  );
28895
29204
  },
28896
29205
  evaluate: (ops, { engine: ce }) => {
@@ -28906,7 +29215,7 @@ var COLLECTIONS_LIBRARY = {
28906
29215
  description: "Return a list of the unique elements of the collection.",
28907
29216
  complexity: 8200,
28908
29217
  signature: "(collection) -> list",
28909
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
29218
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
28910
29219
  evaluate: (ops, { engine: ce }) => {
28911
29220
  if (!ops[0].isFiniteCollection) return void 0;
28912
29221
  const [values, _counts] = tally(ops[0]);
@@ -28918,7 +29227,7 @@ var COLLECTIONS_LIBRARY = {
28918
29227
  wikidata: "Q381060",
28919
29228
  complexity: 8200,
28920
29229
  signature: "(collection, integer | function) -> list",
28921
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
29230
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
28922
29231
  evaluate: ([xs, arg], { engine: ce }) => {
28923
29232
  if (!xs.isFiniteCollection) return void 0;
28924
29233
  const k = toInteger(arg);
@@ -29092,32 +29401,74 @@ var COLLECTIONS_LIBRARY = {
29092
29401
  }
29093
29402
  }
29094
29403
  },
29095
- // Repeat(x) -> [x, x, ...]
29096
- // This is an infinite series. Can use Take(Repeat(x), n) to get a finite series
29097
- // x is evaluated once. Although could use Hold()?
29098
- // So that First(Repeat(Hold(Random(5))), 10) would return 10 random numbers...
29404
+ // Repeat(x) -> [x, x, ...] — infinite sequence
29405
+ // Repeat(x, n) -> [x, x, ..., x] — finite list of n copies
29099
29406
  Repeat: {
29100
- description: "Produce an infinite sequence by repeating a single value.",
29407
+ 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.",
29101
29408
  complexity: 8200,
29102
- signature: "(value: any) -> list",
29409
+ signature: "(value: any, count: integer?) -> list",
29410
+ evaluate: (ops, { engine }) => {
29411
+ if (ops.length !== 2) return void 0;
29412
+ const raw = toInteger(ops[1]);
29413
+ if (raw === null) return void 0;
29414
+ const n = Math.max(0, raw);
29415
+ if (n > engine.maxCollectionSize) return void 0;
29416
+ return engine._fn("List", Array(n).fill(ops[0]));
29417
+ },
29103
29418
  collection: {
29104
- isLazy: (_expr) => true,
29105
- count: () => Infinity,
29106
- isEmpty: (_expr) => false,
29107
- // Never empty
29108
- isFinite: () => false,
29109
- // Infinite collection
29419
+ isLazy: (expr2) => isFunction2(expr2) && expr2.ops?.length === 1,
29420
+ count: (expr2) => {
29421
+ if (!isFunction2(expr2)) return void 0;
29422
+ if (expr2.ops?.length === 2) {
29423
+ const n = toInteger(expr2.op2);
29424
+ return n !== null ? Math.max(0, n) : void 0;
29425
+ }
29426
+ return Infinity;
29427
+ },
29428
+ isEmpty: (expr2) => {
29429
+ if (!isFunction2(expr2)) return void 0;
29430
+ if (expr2.ops?.length === 2) {
29431
+ const n = toInteger(expr2.op2);
29432
+ return n !== null ? n <= 0 : void 0;
29433
+ }
29434
+ return false;
29435
+ },
29436
+ isFinite: (expr2) => isFunction2(expr2) && expr2.ops?.length === 2,
29110
29437
  contains: (expr2, target) => {
29111
29438
  if (!isFunction2(expr2)) return false;
29439
+ if (expr2.ops?.length === 2) {
29440
+ const n = toInteger(expr2.op2);
29441
+ if (n !== null && n <= 0) return false;
29442
+ }
29112
29443
  return expr2.op1.isSame(target);
29113
29444
  },
29114
29445
  iterator: (expr2) => {
29115
29446
  if (!isFunction2(expr2))
29116
29447
  return { next: () => ({ value: void 0, done: true }) };
29448
+ if (expr2.ops?.length === 2) {
29449
+ const n = toInteger(expr2.op2);
29450
+ if (n === null) {
29451
+ return { next: () => ({ value: void 0, done: true }) };
29452
+ }
29453
+ const count = Math.max(0, n);
29454
+ let i = 0;
29455
+ return {
29456
+ next: () => i++ < count ? { value: expr2.op1, done: false } : { value: void 0, done: true }
29457
+ };
29458
+ }
29117
29459
  return { next: () => ({ value: expr2.op1, done: false }) };
29118
29460
  },
29119
- at: (expr2, _index) => {
29461
+ // at is 1-based (consistent with Range, Take, and other collection handlers)
29462
+ at: (expr2, index) => {
29120
29463
  if (!isFunction2(expr2)) return void 0;
29464
+ if (typeof index !== "number") return void 0;
29465
+ if (expr2.ops?.length === 2) {
29466
+ const n = toInteger(expr2.op2);
29467
+ const count = n !== null ? Math.max(0, n) : 0;
29468
+ if (index < 1 || index > count) return void 0;
29469
+ } else {
29470
+ if (index < 1) return void 0;
29471
+ }
29121
29472
  return expr2.op1;
29122
29473
  }
29123
29474
  }
@@ -31403,11 +31754,12 @@ var ARITHMETIC_LIBRARY = [
31403
31754
  );
31404
31755
  }
31405
31756
  },
31406
- // Complex: {
31407
- // // This function is converted during boxing, so unlikely to encounter
31408
- // wikidata: 'Q11567',
31409
- // complexity: 500,
31410
- // },
31757
+ Complex: {
31758
+ description: 'Construct a complex number from real and imaginary parts. Converted directly to a BoxedNumber during boxing; this entry exists so `operatorInfo("Complex")` returns a signature.',
31759
+ wikidata: "Q11567",
31760
+ complexity: 500,
31761
+ signature: "(real: number, imaginary: number) -> complex"
31762
+ },
31411
31763
  Divide: {
31412
31764
  description: "Quotient of a numerator and one or more denominators.",
31413
31765
  wikidata: "Q1226939",
@@ -32757,48 +33109,83 @@ var ARITHMETIC_LIBRARY = [
32757
33109
  }
32758
33110
  },
32759
33111
  Sum: {
32760
- description: "`Sum(f, [a, b])` computes the sum of `f` from `a` to `b`",
33112
+ description: "`Sum(f, [a, b])` computes the sum of `f` from `a` to `b`; `Sum(L)` sums the elements of a collection `L`",
32761
33113
  wikidata: "Q218005",
32762
33114
  complexity: 1e3,
32763
33115
  broadcastable: false,
32764
33116
  scoped: true,
32765
33117
  lazy: true,
32766
- signature: "((number) -> number, bounds:tuple+) -> number",
32767
- canonical: ([body, ...bounds], { scope }) => canonicalBigop("Sum", body, bounds, scope),
32768
- evaluate: ([body, ...indexes], { engine, numericApproximation: numericApproximation2 }) => {
33118
+ signature: "(any, tuple*) -> number",
33119
+ canonical: ([body, ...bounds], { scope, engine: ce }) => {
33120
+ if (bounds.length === 0) {
33121
+ const canon = body?.canonical;
33122
+ if (canon?.isCollection) return ce._fn("Sum", [canon]);
33123
+ }
33124
+ return canonicalBigop("Sum", body, bounds, scope);
33125
+ },
33126
+ evaluate: ([first, ...rest], { engine, numericApproximation: numericApproximation2 }) => {
33127
+ if (rest.length === 0 && first?.isCollection) {
33128
+ if (first.isFiniteCollection !== true) return void 0;
33129
+ const result2 = run(
33130
+ reduceCollection2(
33131
+ first,
33132
+ engine.Zero,
33133
+ (acc, x) => acc.add(x.evaluate({ numericApproximation: numericApproximation2 }))
33134
+ ),
33135
+ engine._timeRemaining
33136
+ );
33137
+ return result2?.evaluate({ numericApproximation: numericApproximation2 }) ?? engine.NaN;
33138
+ }
32769
33139
  const result = run(
32770
33140
  reduceBigOp(
32771
- body,
32772
- indexes,
33141
+ first,
33142
+ rest,
32773
33143
  (acc, x) => acc.add(x.evaluate({ numericApproximation: numericApproximation2 })),
32774
33144
  engine.Zero
32775
33145
  ),
32776
33146
  engine._timeRemaining
32777
33147
  );
32778
- if (result === NON_ENUMERABLE_DOMAIN) {
32779
- return void 0;
32780
- }
33148
+ if (result === NON_ENUMERABLE_DOMAIN) return void 0;
32781
33149
  return result?.evaluate({ numericApproximation: numericApproximation2 }) ?? engine.NaN;
32782
33150
  },
32783
- evaluateAsync: async (xs, { engine, signal, numericApproximation: numericApproximation2 }) => {
33151
+ evaluateAsync: async ([first, ...rest], { engine, signal, numericApproximation: numericApproximation2 }) => {
33152
+ if (rest.length === 0 && first?.isCollection) {
33153
+ if (first.isFiniteCollection !== true) return void 0;
33154
+ const result2 = await runAsync(
33155
+ reduceCollection2(
33156
+ first,
33157
+ engine.Zero,
33158
+ (acc, x) => acc.add(x.evaluate({ numericApproximation: numericApproximation2 }))
33159
+ ),
33160
+ engine._timeRemaining,
33161
+ signal
33162
+ );
33163
+ return result2?.evaluate({ numericApproximation: numericApproximation2 }) ?? engine.NaN;
33164
+ }
32784
33165
  const result = await runAsync(
32785
33166
  reduceBigOp(
32786
- xs[0],
32787
- xs.slice(1),
33167
+ first,
33168
+ rest,
32788
33169
  (acc, x) => acc.add(x.evaluate({ numericApproximation: numericApproximation2 })),
32789
33170
  engine.Zero
32790
33171
  ),
32791
33172
  engine._timeRemaining,
32792
33173
  signal
32793
33174
  );
32794
- if (result === NON_ENUMERABLE_DOMAIN) {
32795
- return void 0;
32796
- }
33175
+ if (result === NON_ENUMERABLE_DOMAIN) return void 0;
32797
33176
  return result?.evaluate({ numericApproximation: numericApproximation2 }) ?? engine.NaN;
32798
33177
  }
32799
33178
  }
32800
33179
  }
32801
33180
  ];
33181
+ function* reduceCollection2(collection, init, combine) {
33182
+ let acc = init;
33183
+ for (const x of collection.each()) {
33184
+ acc = combine(acc, x);
33185
+ yield acc;
33186
+ }
33187
+ return acc;
33188
+ }
32802
33189
  function evaluateAbs(arg) {
32803
33190
  const ce = arg.engine;
32804
33191
  if (isNumber(arg)) {
@@ -43035,7 +43422,7 @@ var COLORS_LIBRARY = {
43035
43422
  var CONTROL_STRUCTURES_LIBRARY = [
43036
43423
  {
43037
43424
  Block: {
43038
- description: "Evaluate a sequence of expressions in a local scope.",
43425
+ description: "Evaluate a sequence of expressions in a local scope, **sequentially**. Each operand is evaluated in order; later operands observe side effects (`Assign`, `Declare`) of earlier operands. The block's value is the value of the last expression. Short-circuiting heads (`Return`, `Break`, `Continue`) terminate the sequence early.\n\nIMPORTANT \u2014 consumers translating *simultaneous* action tuples (e.g. Desmos `(a \u2192 1, b \u2192 a + 1)` where `b` reads the *pre-action* `a`) must rewrite to a snapshot-then-commit Block: bind each RHS to a fresh temp first, then assign the temps to the LHS symbols. See `docs/architecture/actions-and-randomness.md` for the canonical recipe.",
43039
43426
  lazy: true,
43040
43427
  scoped: true,
43041
43428
  signature: "(unknown*) -> unknown",
@@ -43097,7 +43484,7 @@ var CONTROL_STRUCTURES_LIBRARY = [
43097
43484
  evaluateAsync: async (ops, { engine: ce, signal }) => runAsync(runLoop(ops[0], ops.slice(1), ce), ce._timeRemaining, signal)
43098
43485
  },
43099
43486
  When: {
43100
- description: "Conditional value: returns expr when cond holds, undefined otherwise.",
43487
+ description: 'Conditional/restriction value. `When(e, cond)` evaluates to:\n - `e` when `cond` evaluates to `True`\n - `Undefined` when `cond` evaluates to `False` (the "masking rule"; consumers like 2D plotters skip masked points)\n - `When(e, cond_simplified)` when `cond` is indeterminate (holds)\nStacked restrictions canonicalize: `When(When(e, c1), c2)` \u2192 `When(e, And(c1, c2))`.\nCompiles to ternary `(cond) ? (e) : NaN` in JS and GLSL.',
43101
43488
  lazy: true,
43102
43489
  signature: "(expression, boolean) -> any",
43103
43490
  type: ([expr2]) => expr2.type,
@@ -44956,7 +45343,7 @@ var CORE_LIBRARY = [
44956
45343
  evaluate: (ops) => apply(ops[0], ops.slice(1))
44957
45344
  },
44958
45345
  Assign: {
44959
- description: "Assign a value to a symbol or define a sequence",
45346
+ description: "Assign a value to a symbol or define a sequence. The RHS is evaluated immediately and `ce.assign(name, val)` mutates the binding in the current scope chain. When used inside a `Block`, the assignment is visible to subsequent statements in the block (sequential semantics).",
44960
45347
  lazy: true,
44961
45348
  pure: false,
44962
45349
  signature: "(symbol | expression, any) -> any",
@@ -45087,7 +45474,12 @@ var CORE_LIBRARY = [
45087
45474
  evaluate: (ops, { engine: ce }) => {
45088
45475
  const symbolName2 = sym(ops[0].evaluate());
45089
45476
  if (!symbolName2) return void 0;
45477
+ const currentScope = ce.context.lexicalScope;
45478
+ const existing = currentScope.bindings.get(symbolName2);
45479
+ const existingValueDef = existing && isValueDef(existing) ? existing : void 0;
45480
+ const isAutoDeclareHere = !!existingValueDef && existingValueDef.value.inferredType && existingValueDef.value.value === void 0;
45090
45481
  if (!ops[1]) {
45482
+ if (isAutoDeclareHere) return ce.Nothing;
45091
45483
  ce.declare(symbolName2, { inferred: true, type: "unknown" });
45092
45484
  return ce.Nothing;
45093
45485
  }
@@ -45096,6 +45488,11 @@ var CORE_LIBRARY = [
45096
45488
  (isString(t) ? t.string : void 0) ?? sym(t) ?? void 0
45097
45489
  );
45098
45490
  if (!isValidType(type2)) return void 0;
45491
+ if (isAutoDeclareHere && existingValueDef) {
45492
+ existingValueDef.value.type = ce.type(type2);
45493
+ existingValueDef.value.inferredType = false;
45494
+ return ce.Nothing;
45495
+ }
45099
45496
  ce.declare(symbolName2, type2);
45100
45497
  return ce.Nothing;
45101
45498
  }
@@ -45213,33 +45610,41 @@ var CORE_LIBRARY = [
45213
45610
  },
45214
45611
  Random: {
45215
45612
  description: [
45216
- "Random(): Return a random number between 0 and 1",
45217
- "Random(n): Return a random integer between 0 and n-1",
45218
- "Random(m, n): Return a random integer between m and n-1"
45613
+ "Random(): non-deterministic float in [0, 1)",
45614
+ "Random(seed: real): deterministic float in [0, 1) from a real seed",
45615
+ "Random(n: integer): non-deterministic integer in [0, n)",
45616
+ "Random(m: integer, n: integer): non-deterministic integer in [m, n)"
45219
45617
  ],
45220
45618
  pure: false,
45221
- signature: "(lower:integer?, upper:integer?) -> finite_number",
45222
- type: ([lower, upper]) => {
45223
- if (lower === void 0 && upper === void 0) return "finite_number";
45224
- return "finite_integer";
45619
+ // Signature accepts: nothing, one number, or two integers.
45620
+ // Use `number` (not `integer`) for the single-arg case so float seeds
45621
+ // type-check; runtime dispatch differentiates integer vs real.
45622
+ signature: "(number?, integer?) -> finite_number",
45623
+ type: ([first, second]) => {
45624
+ if (first === void 0) return "finite_number";
45625
+ if (second !== void 0) return "finite_integer";
45626
+ if (first.type.matches("integer")) return "finite_integer";
45627
+ return "finite_number";
45225
45628
  },
45226
45629
  sgn: () => "non-negative",
45227
45630
  evaluate: (ops, { engine: ce }) => {
45228
45631
  if (ops.length === 0) return ce.number(Math.random());
45229
- const [lowerOp, upperOp] = ops;
45230
- let lower;
45231
- let upper;
45232
- if (upperOp === void 0) {
45233
- lower = 0;
45234
- upper = Math.floor(lowerOp.re - 1);
45235
- if (isNaN(upper)) upper = 0;
45236
- } else {
45237
- lower = Math.floor(lowerOp.re);
45238
- upper = Math.floor(upperOp.re);
45632
+ const [firstOp, secondOp] = ops;
45633
+ if (secondOp !== void 0) {
45634
+ let lower = Math.floor(firstOp.re);
45635
+ let upper = Math.floor(secondOp.re);
45239
45636
  if (isNaN(lower)) lower = 0;
45240
45637
  if (isNaN(upper)) upper = 0;
45638
+ return ce.number(lower + Math.floor(Math.random() * (upper - lower)));
45241
45639
  }
45242
- return ce.number(lower + Math.floor(Math.random() * (upper - lower)));
45640
+ if (firstOp.type.matches("integer")) {
45641
+ let n = Math.floor(firstOp.re);
45642
+ if (isNaN(n)) n = 0;
45643
+ return ce.number(Math.floor(Math.random() * n));
45644
+ }
45645
+ const seed = firstOp.re;
45646
+ if (isNaN(seed)) return ce.number(0);
45647
+ return ce.number(deterministicRandom(seed));
45243
45648
  }
45244
45649
  },
45245
45650
  // @todo: need review
@@ -45695,6 +46100,14 @@ var CORE_LIBRARY = [
45695
46100
  To: {
45696
46101
  description: "Action arrow / mapping (`a \\to b`) \u2014 opaque typed head.",
45697
46102
  signature: "(any, any) -> nothing"
46103
+ },
46104
+ Colon: {
46105
+ description: "Type annotation (`a : b`) \u2014 opaque typed head.",
46106
+ signature: "(any, any) -> expression"
46107
+ },
46108
+ Prime: {
46109
+ description: "Derivative or prime notation (`f'`, `f^{(n)}`) \u2014 opaque typed head until a derivative library handler runs.",
46110
+ signature: "(any, integer?) -> expression"
45698
46111
  }
45699
46112
  }
45700
46113
  ];
@@ -50735,18 +51148,28 @@ var STATISTICS_LIBRARY = [
50735
51148
  },
50736
51149
  {
50737
51150
  Sample: {
50738
- description: "Return a random sample of k elements from the collection, without replacement.",
51151
+ description: "Return a random sample of k elements from the collection, without replacement. With an optional `seed` argument, the sample is deterministic.",
50739
51152
  complexity: 8200,
50740
- signature: "(collection, integer) -> list",
50741
- evaluate: ([xs, nArg], { engine: ce }) => {
51153
+ signature: "(collection, integer, real?) -> list",
51154
+ evaluate: ([xs, nArg, seedArg], { engine: ce }) => {
50742
51155
  if (!xs.isFiniteCollection) return void 0;
50743
51156
  const k = toInteger(nArg);
50744
51157
  if (k === null || k < 0) return void 0;
50745
51158
  const data = Array.from(xs.each());
50746
51159
  if (k > data.length) return void 0;
50747
- for (let i = data.length - 1; i > 0; i--) {
50748
- const j = Math.floor(Math.random() * (i + 1));
50749
- [data[i], data[j]] = [data[j], data[i]];
51160
+ const seed = seedArg?.re;
51161
+ if (seed !== void 0 && !Number.isNaN(seed)) {
51162
+ let s = seed;
51163
+ for (let i = data.length - 1; i > 0; i--) {
51164
+ const j = Math.floor(deterministicRandom(s) * (i + 1));
51165
+ [data[i], data[j]] = [data[j], data[i]];
51166
+ s = nextSeed(s);
51167
+ }
51168
+ } else {
51169
+ for (let i = data.length - 1; i > 0; i--) {
51170
+ const j = Math.floor(Math.random() * (i + 1));
51171
+ [data[i], data[j]] = [data[j], data[i]];
51172
+ }
50750
51173
  }
50751
51174
  const sample = data.slice(0, k);
50752
51175
  return ce.function("List", sample);
@@ -53567,6 +53990,20 @@ var BoxedFunction = class extends _BoxedExpression {
53567
53990
  if (results.length === 1) return results[0];
53568
53991
  return this.engine._fn("List", results);
53569
53992
  }
53993
+ if (def instanceof _BoxedOperatorDefinition && def._isLambda && this.ops.some((x) => isFiniteIndexedCollection(x)) && paramsAreScalar(def)) {
53994
+ const items = zip(this._ops);
53995
+ if (items) {
53996
+ const results = [];
53997
+ while (true) {
53998
+ const { done, value } = items.next();
53999
+ if (done) break;
54000
+ results.push(
54001
+ this.engine._fn(this.operator, value).evaluate(options)
54002
+ );
54003
+ }
54004
+ return this.engine._fn("List", results);
54005
+ }
54006
+ }
53570
54007
  if (materialization !== false && !def.evaluate && this.isLazyCollection)
53571
54008
  return materialize(this, def, options);
53572
54009
  const tail = holdMap(this, (x) => x.evaluate(options));
@@ -53613,6 +54050,22 @@ var BoxedFunction = class extends _BoxedExpression {
53613
54050
  (resolved) => this.engine._fn("List", resolved)
53614
54051
  );
53615
54052
  }
54053
+ if (def instanceof _BoxedOperatorDefinition && def._isLambda && this.ops.some((x) => isFiniteIndexedCollection(x)) && paramsAreScalar(def)) {
54054
+ const items = zip(this._ops);
54055
+ if (items) {
54056
+ const results = [];
54057
+ while (true) {
54058
+ const { done, value } = items.next();
54059
+ if (done) break;
54060
+ results.push(
54061
+ this.engine._fn(this.operator, value).evaluateAsync(options)
54062
+ );
54063
+ }
54064
+ return Promise.all(results).then(
54065
+ (resolved) => this.engine._fn("List", resolved)
54066
+ );
54067
+ }
54068
+ }
53616
54069
  const tail = await holdMapAsync(
53617
54070
  this,
53618
54071
  async (x) => await x.evaluateAsync(options)
@@ -53827,8 +54280,47 @@ function applyFunctionLiteral(expr2, def, options) {
53827
54280
  const ops = expr2.ops.map((x) => x.evaluate(options));
53828
54281
  if (!value || value.type.isUnknown)
53829
54282
  return expr2.engine.function(expr2.operator, ops);
54283
+ if (ops.some((x) => isFiniteIndexedCollection(x)) && paramsAreScalar(value.type.type)) {
54284
+ const items = zip(ops);
54285
+ if (items) {
54286
+ const results = [];
54287
+ while (true) {
54288
+ const { done, value: zipped } = items.next();
54289
+ if (done) break;
54290
+ results.push(apply(value, zipped).evaluate(options));
54291
+ }
54292
+ return expr2.engine._fn("List", results);
54293
+ }
54294
+ }
53830
54295
  return apply(value, ops);
53831
54296
  }
54297
+ function paramsAreScalar(source) {
54298
+ const sigType = isOperatorDefinition(source) ? source.signature?.type : source;
54299
+ if (!sigType || typeof sigType === "string") return true;
54300
+ if (sigType.kind !== "signature") return true;
54301
+ const args = [
54302
+ ...sigType.args ?? [],
54303
+ ...sigType.optArgs ?? [],
54304
+ ...sigType.variadicArg ? [sigType.variadicArg] : []
54305
+ ];
54306
+ return args.every((arg) => isScalarType(arg.type));
54307
+ }
54308
+ function isOperatorDefinition(source) {
54309
+ return typeof source === "object" && source !== null && "signature" in source;
54310
+ }
54311
+ function isScalarType(t) {
54312
+ if (typeof t === "string") {
54313
+ if (t === "collection" || t === "indexed_collection" || t === "list" || t === "tuple" || t === "set" || t === "dictionary" || t === "record" || t === "function")
54314
+ return false;
54315
+ return true;
54316
+ }
54317
+ if (t.kind === "collection" || t.kind === "indexed_collection" || t.kind === "list" || t.kind === "tuple" || t.kind === "set" || t.kind === "dictionary" || t.kind === "record" || t.kind === "signature")
54318
+ return false;
54319
+ if (t.kind === "union" || t.kind === "intersection")
54320
+ return t.types.every((x) => isScalarType(x));
54321
+ if (t.kind === "negation") return isScalarType(t.type);
54322
+ return true;
54323
+ }
53832
54324
  function materialize(expr2, def, options) {
53833
54325
  if (!expr2.isValid || options?.materialization === false) return expr2;
53834
54326
  let materialization = options?.materialization ?? false;
@@ -53836,6 +54328,11 @@ function materialize(expr2, def, options) {
53836
54328
  materialization = DEFAULT_MATERIALIZATION;
53837
54329
  const isIndexed = expr2.isIndexedCollection;
53838
54330
  const isFinite2 = expr2.isFiniteCollection;
54331
+ if (isIndexed && isFinite2) {
54332
+ const count = expr2.count;
54333
+ if (count !== void 0 && count > expr2.engine.maxCollectionSize)
54334
+ return expr2;
54335
+ }
53839
54336
  const xs = [];
53840
54337
  if (!expr2.isEmptyCollection) {
53841
54338
  if (!isIndexed || !isFinite2) {
@@ -54063,7 +54560,7 @@ var BoxedDictionary = class _BoxedDictionary extends _BoxedExpression {
54063
54560
  const eltType = widen(
54064
54561
  ...Object.values(this._keyValues).map((op) => op.type.type)
54065
54562
  );
54066
- this._type = this.engine.type(`dictionary<${eltType}>`);
54563
+ this._type = new BoxedType({ kind: "dictionary", values: eltType });
54067
54564
  return this._type;
54068
54565
  }
54069
54566
  get isPure() {
@@ -54341,6 +54838,7 @@ function box(ce, expr2, options) {
54341
54838
  }
54342
54839
  if (typeof expr2 === "number" || expr2 instanceof BigDecimal || expr2 instanceof Complex)
54343
54840
  return ce.number(expr2);
54841
+ if (typeof expr2 === "boolean") return ce.symbol(expr2 ? "True" : "False");
54344
54842
  if (typeof expr2 === "string") {
54345
54843
  if (matchesSymbol(expr2)) {
54346
54844
  const sym2 = symbol(expr2);
@@ -55519,6 +56017,13 @@ var BaseCompiler = class _BaseCompiler {
55519
56017
  * GLSL (no dynamic arrays, no push). A compile-time error is thrown.
55520
56018
  * TODO(E3-GLSL): support GLSL multi-Element via a pre-declared fixed-size
55521
56019
  * array or by unrolling when bounds are known at compile time.
56020
+ *
56021
+ * Known issue (imperative form): the IIFE generated by form (1) has no
56022
+ * `return` statement, so `Loop(body, Element(i, Range(lo, hi)))` compiled
56023
+ * to JS evaluates to `undefined` at runtime, while CE evaluation returns a
56024
+ * `List` of body values. See `test/compute-engine/a1-c1-compile-parity.test.ts`
56025
+ * ("Loop compiles in JS") for the verify-only test that locks in the
56026
+ * current behavior.
55522
56027
  */
55523
56028
  static compileForLoop(args, target) {
55524
56029
  if (!args[0]) throw new Error("Loop: no body");
@@ -60155,8 +60660,8 @@ function assumeInequality(proposition) {
60155
60660
  }
60156
60661
  if (effectiveOp === "greater" || effectiveOp === "greaterEqual") {
60157
60662
  const isStrict = effectiveOp === "greater";
60158
- if (bounds.lowerBound !== void 0) {
60159
- const lowerVal = isNumber(bounds.lowerBound) ? bounds.lowerBound.numericValue : void 0;
60663
+ if (bounds.lower !== void 0) {
60664
+ const lowerVal = isNumber(bounds.lower) ? bounds.lower.numericValue : void 0;
60160
60665
  if (typeof lowerVal === "number" && isFinite(lowerVal)) {
60161
60666
  if (isStrict) {
60162
60667
  if (lowerVal > k) return "tautology";
@@ -60168,8 +60673,8 @@ function assumeInequality(proposition) {
60168
60673
  }
60169
60674
  }
60170
60675
  }
60171
- if (bounds.upperBound !== void 0) {
60172
- const upperVal = isNumber(bounds.upperBound) ? bounds.upperBound.numericValue : void 0;
60676
+ if (bounds.upper !== void 0) {
60677
+ const upperVal = isNumber(bounds.upper) ? bounds.upper.numericValue : void 0;
60173
60678
  if (typeof upperVal === "number" && isFinite(upperVal)) {
60174
60679
  if (isStrict) {
60175
60680
  if (upperVal < k) return "contradiction";
@@ -60184,8 +60689,8 @@ function assumeInequality(proposition) {
60184
60689
  }
60185
60690
  } else {
60186
60691
  const isStrict = effectiveOp === "less";
60187
- if (bounds.upperBound !== void 0) {
60188
- const upperVal = isNumber(bounds.upperBound) ? bounds.upperBound.numericValue : void 0;
60692
+ if (bounds.upper !== void 0) {
60693
+ const upperVal = isNumber(bounds.upper) ? bounds.upper.numericValue : void 0;
60189
60694
  if (typeof upperVal === "number" && isFinite(upperVal)) {
60190
60695
  if (isStrict) {
60191
60696
  if (upperVal < k) return "tautology";
@@ -60196,8 +60701,8 @@ function assumeInequality(proposition) {
60196
60701
  }
60197
60702
  }
60198
60703
  }
60199
- if (bounds.lowerBound !== void 0) {
60200
- const lowerVal = isNumber(bounds.lowerBound) ? bounds.lowerBound.numericValue : void 0;
60704
+ if (bounds.lower !== void 0) {
60705
+ const lowerVal = isNumber(bounds.lower) ? bounds.lower.numericValue : void 0;
60201
60706
  if (typeof lowerVal === "number" && isFinite(lowerVal)) {
60202
60707
  if (isStrict) {
60203
60708
  if (lowerVal > k) return "contradiction";
@@ -60425,7 +60930,7 @@ function ask(ce, pattern) {
60425
60930
  const patOp1B2 = pat.op1;
60426
60931
  if (isSymbol2(patOp1B2)) {
60427
60932
  const bounds = getInequalityBoundsFromAssumptions(ce, patOp1B2.symbol);
60428
- const bound = isLower ? bounds.lowerBound : bounds.upperBound;
60933
+ const bound = isLower ? bounds.lower : bounds.upper;
60429
60934
  const strictOk = isLower ? bounds.lowerStrict : bounds.upperStrict;
60430
60935
  if (bound !== void 0 && (!isStrict || strictOk === true))
60431
60936
  pushResult({ [boundWildcard]: bound });
@@ -60435,7 +60940,7 @@ function ask(ce, pattern) {
60435
60940
  if (symbolWildcard && !symbolWildcard.startsWith("__")) {
60436
60941
  for (const s of candidatesFromAssumptions()) {
60437
60942
  const bounds = getInequalityBoundsFromAssumptions(ce, s);
60438
- const bound = isLower ? bounds.lowerBound : bounds.upperBound;
60943
+ const bound = isLower ? bounds.lower : bounds.upper;
60439
60944
  const strictOk = isLower ? bounds.lowerStrict : bounds.upperStrict;
60440
60945
  if (bound === void 0 || isStrict && strictOk !== true)
60441
60946
  continue;
@@ -61467,6 +61972,7 @@ var JAVASCRIPT_FUNCTIONS = {
61467
61972
  return `_SYS.cexp(${compile3(args[0])})`;
61468
61973
  return `Math.exp(${compile3(args[0])})`;
61469
61974
  },
61975
+ First: (args, compile3) => `${compile3(args[0])}[0]`,
61470
61976
  Floor: (args, compile3) => {
61471
61977
  if (BaseCompiler.isIntegerValued(args[0])) return compile3(args[0]);
61472
61978
  return `Math.floor(${compile3(args[0])})`;
@@ -61625,7 +62131,20 @@ var JAVASCRIPT_FUNCTIONS = {
61625
62131
  if (nConst !== void 0) return `Math.pow(${compile3(arg)}, ${1 / nConst})`;
61626
62132
  return `Math.pow(${compile3(arg)}, 1 / (${compile3(exp3)}))`;
61627
62133
  },
61628
- Random: "Math.random",
62134
+ Random: (args, compile3) => {
62135
+ if (args.length === 0) return "Math.random()";
62136
+ if (args.length === 2) {
62137
+ const m = compile3(args[0]);
62138
+ const n = compile3(args[1]);
62139
+ return `((${m}) + Math.floor(Math.random() * ((${n}) - (${m}))))`;
62140
+ }
62141
+ const arg = args[0];
62142
+ if (BaseCompiler.isIntegerValued(arg)) {
62143
+ return `Math.floor(Math.random() * (${compile3(arg)}))`;
62144
+ }
62145
+ const a = compile3(arg);
62146
+ return `(() => { const _s = (${a}) * 12.9898; const _v = Math.sin(_s) * 43758.5453; return _v - Math.floor(_v); })()`;
62147
+ },
61629
62148
  Round: (args, compile3) => {
61630
62149
  if (BaseCompiler.isIntegerValued(args[0])) return compile3(args[0]);
61631
62150
  return `Math.round(${compile3(args[0])})`;
@@ -61653,6 +62172,7 @@ var JAVASCRIPT_FUNCTIONS = {
61653
62172
  if (BaseCompiler.isComplexValued(arg)) return `_SYS.csech(${compile3(arg)})`;
61654
62173
  return `1 / Math.cosh(${compile3(arg)})`;
61655
62174
  },
62175
+ Second: (args, compile3) => `${compile3(args[0])}[1]`,
61656
62176
  Heaviside: "_SYS.heaviside",
61657
62177
  Sign: "Math.sign",
61658
62178
  Sinc: "_SYS.sinc",
@@ -61685,6 +62205,7 @@ var JAVASCRIPT_FUNCTIONS = {
61685
62205
  return `_SYS.ctanh(${compile3(args[0])})`;
61686
62206
  return `Math.tanh(${compile3(args[0])})`;
61687
62207
  },
62208
+ Third: (args, compile3) => `${compile3(args[0])}[2]`,
61688
62209
  Mod: ([a, b], compile3) => {
61689
62210
  if (a === null || b === null) throw new Error("Mod: missing argument");
61690
62211
  const ca = compile3(a);
@@ -62964,6 +63485,14 @@ var GPU_FUNCTIONS = {
62964
63485
  return `exp(${compile3(args[0])})`;
62965
63486
  },
62966
63487
  Exp2: "exp2",
63488
+ // Component access — assumes the argument compiles to a vec2/vec3/vec4
63489
+ // (the common case for 2D/3D points). For 5+-element tuples that compile
63490
+ // to `float[N]` arrays, swizzle access is invalid GLSL and the shader
63491
+ // will fail to compile; that's an edge case `First`/`Second`/`Third`
63492
+ // aren't designed for. Vec swizzles are identical between GLSL and WGSL.
63493
+ First: (args, compile3) => `${compile3(args[0])}.x`,
63494
+ Second: (args, compile3) => `${compile3(args[0])}.y`,
63495
+ Third: (args, compile3) => `${compile3(args[0])}.z`,
62967
63496
  Floor: (args, compile3) => {
62968
63497
  if (BaseCompiler.isIntegerValued(args[0])) return compile3(args[0]);
62969
63498
  return `floor(${compile3(args[0])})`;
@@ -63441,6 +63970,39 @@ var GPU_FUNCTIONS = {
63441
63970
  // Sum/Product — unrolled or for-loop
63442
63971
  Sum: (args, compile3, target) => compileGPUSumProduct("Sum", args, compile3, target),
63443
63972
  Product: (args, compile3, target) => compileGPUSumProduct("Product", args, compile3, target),
63973
+ // Range — inline constant array literal (bounds must be compile-time constants)
63974
+ Range: (args, _compile2, target) => {
63975
+ if (args.length < 2 || args.length > 3) {
63976
+ throw new Error(
63977
+ "Range: GPU compile expects 2 or 3 arguments (lo, hi, step?)"
63978
+ );
63979
+ }
63980
+ const lo = args[0].re;
63981
+ const hi = args[1].re;
63982
+ const step = args.length === 3 ? args[2].re : 1;
63983
+ if (!Number.isFinite(lo) || !Number.isFinite(hi) || !Number.isFinite(step)) {
63984
+ throw new Error(
63985
+ "Range: GPU compile requires constant numeric bounds (non-constant ranges must be materialized at JS host then uploaded as a uniform)"
63986
+ );
63987
+ }
63988
+ if (step === 0) throw new Error("Range: step cannot be zero");
63989
+ const count = Math.max(0, Math.floor((hi - lo) / step) + 1);
63990
+ if (count === 0) {
63991
+ throw new Error(
63992
+ "Range: empty range (lo > hi for positive step, or lo < hi for negative step)"
63993
+ );
63994
+ }
63995
+ if (count > 256) {
63996
+ throw new Error(
63997
+ `Range: GPU compile inlines ranges up to 256 elements (got ${count})`
63998
+ );
63999
+ }
64000
+ const values = [];
64001
+ for (let i = 0; i < count; i++) values.push(lo + i * step);
64002
+ const isWGSL = target.language === "wgsl";
64003
+ const arrayType = isWGSL ? `array<f32, ${count}>` : `float[${count}]`;
64004
+ return `${arrayType}(${values.map(formatGPUNumber).join(", ")})`;
64005
+ },
63444
64006
  // Loop — GPU for-loop (no IIFE, no let)
63445
64007
  Loop: (args, _compile2, target) => {
63446
64008
  if (!args[0]) throw new Error("Loop: no body");
@@ -63469,6 +64031,134 @@ var GPU_FUNCTIONS = {
63469
64031
  ${bodyCode};
63470
64032
  }`;
63471
64033
  },
64034
+ // Statistical functions
64035
+ /**
64036
+ * GCD of two scalar arguments.
64037
+ *
64038
+ * Uses a preamble helper `_gpu_gcd` (Euclidean algorithm via `mod`).
64039
+ * Only two-argument form is supported in GPU targets.
64040
+ */
64041
+ GCD: (args, compile3) => {
64042
+ if (args.length < 2) throw new Error("GCD: need at least two arguments");
64043
+ if (args.length > 2)
64044
+ throw new Error("GCD: GPU target supports only two-argument GCD");
64045
+ const a = args[0];
64046
+ const b = args[1];
64047
+ if (a === null || b === null) throw new Error("GCD: missing argument");
64048
+ return `_gpu_gcd(${compile3(a)}, ${compile3(b)})`;
64049
+ },
64050
+ /**
64051
+ * Variance of a compile-time-known list.
64052
+ *
64053
+ * Accepts either a single `List(...)` argument or N scalar arguments.
64054
+ * Generates fully inline code: computes mean then sum of squared deviations,
64055
+ * divided by (N-1) for sample variance (matches JS `_SYS.variance`).
64056
+ */
64057
+ Variance: (args, compile3) => {
64058
+ let elems;
64059
+ if (args.length === 1 && isFunction2(args[0], "List")) {
64060
+ elems = args[0].ops;
64061
+ } else if (args.length >= 2) {
64062
+ elems = args;
64063
+ } else {
64064
+ throw new Error(
64065
+ "Variance: GPU target requires a List argument or at least 2 scalar arguments"
64066
+ );
64067
+ }
64068
+ const n = elems.length;
64069
+ if (n < 2) throw new Error("Variance: need at least 2 elements");
64070
+ const compiled = elems.map((e) => compile3(e));
64071
+ const sum = compiled.join(" + ");
64072
+ const mean2 = `((${sum}) / ${formatGPUNumber(n)})`;
64073
+ const sqDiffs = compiled.map((c) => `(${c} - ${mean2}) * (${c} - ${mean2})`).join(" + ");
64074
+ return `((${sqDiffs}) / ${formatGPUNumber(n - 1)})`;
64075
+ },
64076
+ /**
64077
+ * Median of a compile-time-known list.
64078
+ *
64079
+ * Accepts either a single `List(...)` argument or N scalar arguments.
64080
+ * For N ≤ 8: generates a fully unrolled inline sorting network followed by
64081
+ * a middle-element pick. For larger N, throws (too large to inline cleanly).
64082
+ *
64083
+ * The sorting network uses the "odd-even merge sort" comparator pattern
64084
+ * inlined as `min`/`max` calls — no GPU statements required.
64085
+ */
64086
+ Median: (args, compile3) => {
64087
+ let elems;
64088
+ if (args.length === 1 && isFunction2(args[0], "List")) {
64089
+ elems = args[0].ops;
64090
+ } else if (args.length >= 1) {
64091
+ elems = args;
64092
+ } else {
64093
+ throw new Error(
64094
+ "Median: GPU target requires a List argument or at least 1 scalar argument"
64095
+ );
64096
+ }
64097
+ const n = elems.length;
64098
+ if (n === 0) throw new Error("Median: empty list");
64099
+ if (n > 8) {
64100
+ throw new Error(
64101
+ `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.`
64102
+ );
64103
+ }
64104
+ const compiled = elems.map((e) => compile3(e));
64105
+ if (n === 1) return compiled[0];
64106
+ return `_gpu_median_${n}(${compiled.join(", ")})`;
64107
+ },
64108
+ /**
64109
+ * Deterministic pseudorandom for GPU.
64110
+ *
64111
+ * All emitted forms return a GLSL `float` (or WGSL `f32`) so the result
64112
+ * composes with surrounding float arithmetic without explicit casts. The
64113
+ * "integer-bound" forms return an integer-valued float (the result of
64114
+ * `floor`), matching the convention used by `Floor` and other ostensibly
64115
+ * integer-returning operators in this target.
64116
+ *
64117
+ * - 0 args (GLSL only): fall back to a fragment-coord-derived seed.
64118
+ * Only meaningful in fragment shaders (gl_FragCoord is FS-only).
64119
+ * - 0 args (WGSL): throws — WGSL has no built-in fragment coordinate;
64120
+ * caller must provide an explicit seed.
64121
+ * - 1 arg, real-typed: `_gpu_random(seed)` — deterministic float in [0, 1)
64122
+ * - 1 arg, integer-typed: `floor(_gpu_random(float(n)) * float(n))` —
64123
+ * integer-valued float in {0, 1, ..., n-1}. The seed is derived from
64124
+ * `n` itself, so the result is per-pixel-and-n deterministic in GLSL.
64125
+ * - 2 args (integer m, n): float in [m, n), seeded from gl_FragCoord.
64126
+ *
64127
+ * JS-side `Random` has matching semantics (see `library/core.ts`'s
64128
+ * polymorphic dispatch). JS↔GLSL parity is approximate — same seed yields
64129
+ * a similar value, not bit-identical, due to fp64 vs fp32 and platform
64130
+ * `sin` differences.
64131
+ */
64132
+ Random: (args, compile3, target) => {
64133
+ if (args.length === 0) {
64134
+ if (target.language === "wgsl") {
64135
+ throw new Error(
64136
+ "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."
64137
+ );
64138
+ }
64139
+ return "_gpu_random(gl_FragCoord.x + gl_FragCoord.y * 1024.0)";
64140
+ }
64141
+ if (args.length === 1) {
64142
+ const arg = args[0];
64143
+ if (BaseCompiler.isIntegerValued(arg)) {
64144
+ const compiled = compile3(arg);
64145
+ return `floor(_gpu_random(float(${compiled})) * float(${compiled}))`;
64146
+ }
64147
+ return `_gpu_random(${compile3(arg)})`;
64148
+ }
64149
+ if (args.length === 2) {
64150
+ if (target.language === "wgsl") {
64151
+ throw new Error(
64152
+ "Random(m, n): WGSL compile requires explicit seeding. Use a seeded variant or compute the integer range manually."
64153
+ );
64154
+ }
64155
+ const m = compile3(args[0]);
64156
+ const n = compile3(args[1]);
64157
+ const seed = "_gpu_random(gl_FragCoord.x + gl_FragCoord.y * 1024.0)";
64158
+ return `(float(${m}) + floor(${seed} * float((${n}) - (${m}))))`;
64159
+ }
64160
+ throw new Error("Random: GPU compile expects 0, 1, or 2 arguments");
64161
+ },
63472
64162
  // Function (lambda) — not supported in GPU
63473
64163
  Function: () => {
63474
64164
  throw new Error(
@@ -64068,6 +64758,212 @@ fn _fractal_julia(z_in: vec2f, c: vec2f, maxIter: i32) -> f32 {
64068
64758
  return 1.0;
64069
64759
  }
64070
64760
  `;
64761
+ var GPU_GCD_PREAMBLE_GLSL = `
64762
+ float _gpu_gcd(float a, float b) {
64763
+ a = abs(a); b = abs(b);
64764
+ for (int i = 0; i < 32; i++) {
64765
+ if (b < 0.5) break;
64766
+ float t = mod(a, b);
64767
+ a = b;
64768
+ b = t;
64769
+ }
64770
+ return a;
64771
+ }
64772
+ `;
64773
+ var GPU_GCD_PREAMBLE_WGSL = `
64774
+ fn _gpu_gcd(a_in: f32, b_in: f32) -> f32 {
64775
+ var a = abs(a_in); var b = abs(b_in);
64776
+ for (var i: i32 = 0; i < 32; i++) {
64777
+ if (b < 0.5) { break; }
64778
+ let t = a % b;
64779
+ a = b;
64780
+ b = t;
64781
+ }
64782
+ return a;
64783
+ }
64784
+ `;
64785
+ var GPU_RANDOM_PREAMBLE_GLSL = `
64786
+ // Deterministic pseudorandom in [0, 1) from a float seed.
64787
+ // Standard fract-sin hash; reproducible across runs for the same seed.
64788
+ // Note: this hash exhibits visible banding near seed \u2248 k\u03C0 for integer k.
64789
+ // For high-quality shader random, callers should use a more robust hash
64790
+ // (e.g. PCG or xxHash) and pre-seed it appropriately.
64791
+ float _gpu_random(float seed) {
64792
+ return fract(sin(seed * 12.9898) * 43758.5453);
64793
+ }
64794
+ `;
64795
+ var GPU_RANDOM_PREAMBLE_WGSL = `
64796
+ // Deterministic pseudorandom in [0, 1) from a float seed.
64797
+ // Standard fract-sin hash; reproducible across runs for the same seed.
64798
+ // Note: this hash exhibits visible banding near seed \u2248 k\u03C0 for integer k.
64799
+ // For high-quality shader random, callers should use a more robust hash
64800
+ // (e.g. PCG or xxHash) and pre-seed it appropriately.
64801
+ fn _gpu_random(seed: f32) -> f32 {
64802
+ return fract(sin(seed * 12.9898) * 43758.5453);
64803
+ }
64804
+ `;
64805
+ var GPU_MEDIAN_PREAMBLE_GLSL = `
64806
+ float _gpu_median_2(float a, float b) {
64807
+ return (a + b) * 0.5;
64808
+ }
64809
+ float _gpu_median_3(float a, float b, float c) {
64810
+ return max(min(a, b), min(max(a, b), c));
64811
+ }
64812
+ float _gpu_median_4(float a, float b, float c, float d) {
64813
+ float lo = max(min(a, b), min(c, d));
64814
+ float hi = min(max(a, b), max(c, d));
64815
+ return (lo + hi) * 0.5;
64816
+ }
64817
+ float _gpu_median_5(float a, float b, float c, float d, float e) {
64818
+ // 9-comparator Bose-Nelson sort; v2 holds the median.
64819
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e;
64820
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
64821
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
64822
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
64823
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
64824
+ t=min(v0,v3); v3=max(v0,v3); v0=t;
64825
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
64826
+ t=min(v1,v4); v4=max(v1,v4); v1=t;
64827
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
64828
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
64829
+ return v2;
64830
+ }
64831
+ float _gpu_median_6(float a, float b, float c, float d, float e, float f) {
64832
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f;
64833
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
64834
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
64835
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
64836
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
64837
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
64838
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
64839
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
64840
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
64841
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
64842
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
64843
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
64844
+ return (v2 + v3) * 0.5;
64845
+ }
64846
+ float _gpu_median_7(float a, float b, float c, float d, float e, float f, float g) {
64847
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f,v6=g;
64848
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
64849
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
64850
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
64851
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
64852
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
64853
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
64854
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
64855
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
64856
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
64857
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
64858
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
64859
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
64860
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
64861
+ return v3;
64862
+ }
64863
+ float _gpu_median_8(float a, float b, float c, float d, float e, float f, float g, float h) {
64864
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f,v6=g,v7=h;
64865
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
64866
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
64867
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
64868
+ t=min(v6,v7); v7=max(v6,v7); v6=t;
64869
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
64870
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
64871
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
64872
+ t=min(v5,v7); v7=max(v5,v7); v5=t;
64873
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
64874
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
64875
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
64876
+ t=min(v3,v7); v7=max(v3,v7); v3=t;
64877
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
64878
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
64879
+ t=min(v5,v6); v6=max(v5,v6); v5=t;
64880
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
64881
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
64882
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
64883
+ return (v3 + v4) * 0.5;
64884
+ }
64885
+ `;
64886
+ var GPU_MEDIAN_PREAMBLE_WGSL = `
64887
+ fn _gpu_median_2(a: f32, b: f32) -> f32 {
64888
+ return (a + b) * 0.5;
64889
+ }
64890
+ fn _gpu_median_3(a: f32, b: f32, c: f32) -> f32 {
64891
+ return max(min(a, b), min(max(a, b), c));
64892
+ }
64893
+ fn _gpu_median_4(a: f32, b: f32, c: f32, d: f32) -> f32 {
64894
+ let lo = max(min(a, b), min(c, d));
64895
+ let hi = min(max(a, b), max(c, d));
64896
+ return (lo + hi) * 0.5;
64897
+ }
64898
+ fn _gpu_median_5(a: f32, b: f32, c: f32, d: f32, e: f32) -> f32 {
64899
+ // 9-comparator Bose-Nelson sort; v2 holds the median.
64900
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var t: f32;
64901
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
64902
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
64903
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
64904
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
64905
+ t=min(v0,v3); v3=max(v0,v3); v0=t;
64906
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
64907
+ t=min(v1,v4); v4=max(v1,v4); v1=t;
64908
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
64909
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
64910
+ return v2;
64911
+ }
64912
+ fn _gpu_median_6(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) -> f32 {
64913
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var v5=f; var t: f32;
64914
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
64915
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
64916
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
64917
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
64918
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
64919
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
64920
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
64921
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
64922
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
64923
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
64924
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
64925
+ return (v2 + v3) * 0.5;
64926
+ }
64927
+ fn _gpu_median_7(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32, g: f32) -> f32 {
64928
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var v5=f; var v6=g; var t: f32;
64929
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
64930
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
64931
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
64932
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
64933
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
64934
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
64935
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
64936
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
64937
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
64938
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
64939
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
64940
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
64941
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
64942
+ return v3;
64943
+ }
64944
+ fn _gpu_median_8(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32, g: f32, h: f32) -> f32 {
64945
+ 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;
64946
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
64947
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
64948
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
64949
+ t=min(v6,v7); v7=max(v6,v7); v6=t;
64950
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
64951
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
64952
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
64953
+ t=min(v5,v7); v7=max(v5,v7); v5=t;
64954
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
64955
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
64956
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
64957
+ t=min(v3,v7); v7=max(v3,v7); v3=t;
64958
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
64959
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
64960
+ t=min(v5,v6); v6=max(v5,v6); v5=t;
64961
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
64962
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
64963
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
64964
+ return (v3 + v4) * 0.5;
64965
+ }
64966
+ `;
64071
64967
  var GPU_COLOR_PREAMBLE_GLSL = `
64072
64968
  float _gpu_srgb_to_linear(float c) {
64073
64969
  if (c <= 0.04045) return c / 12.92;
@@ -64745,6 +65641,12 @@ var GPUShaderTarget = class {
64745
65641
  if (code.includes("_fractal_")) {
64746
65642
  preamble += this.languageId === "wgsl" ? GPU_FRACTAL_PREAMBLE_WGSL : GPU_FRACTAL_PREAMBLE_GLSL;
64747
65643
  }
65644
+ if (code.includes("_gpu_random"))
65645
+ preamble += this.languageId === "wgsl" ? GPU_RANDOM_PREAMBLE_WGSL : GPU_RANDOM_PREAMBLE_GLSL;
65646
+ if (code.includes("_gpu_gcd"))
65647
+ preamble += this.languageId === "wgsl" ? GPU_GCD_PREAMBLE_WGSL : GPU_GCD_PREAMBLE_GLSL;
65648
+ if (code.includes("_gpu_median_"))
65649
+ preamble += this.languageId === "wgsl" ? GPU_MEDIAN_PREAMBLE_WGSL : GPU_MEDIAN_PREAMBLE_GLSL;
64748
65650
  if (code.includes("_gpu_srgb_to") || code.includes("_gpu_oklab") || code.includes("_gpu_oklch") || code.includes("_gpu_color_mix") || code.includes("_gpu_apca")) {
64749
65651
  preamble += this.languageId === "wgsl" ? GPU_COLOR_PREAMBLE_WGSL : GPU_COLOR_PREAMBLE_GLSL;
64750
65652
  }
@@ -66970,6 +67872,7 @@ var EngineRuntimeState = class {
66970
67872
  _timeLimit = 2e3;
66971
67873
  _iterationLimit = 1024;
66972
67874
  _recursionLimit = 1024;
67875
+ _maxCollectionSize = 1e4;
66973
67876
  _deadline = void 0;
66974
67877
  _isVerifying = false;
66975
67878
  get timeLimit() {
@@ -66990,6 +67893,12 @@ var EngineRuntimeState = class {
66990
67893
  set recursionLimit(value) {
66991
67894
  this._recursionLimit = value <= 0 ? Number.POSITIVE_INFINITY : value;
66992
67895
  }
67896
+ get maxCollectionSize() {
67897
+ return this._maxCollectionSize;
67898
+ }
67899
+ set maxCollectionSize(value) {
67900
+ this._maxCollectionSize = value <= 0 ? Number.POSITIVE_INFINITY : value;
67901
+ }
66993
67902
  get deadline() {
66994
67903
  return this._deadline;
66995
67904
  }
@@ -69028,6 +69937,23 @@ var ComputeEngine = class _ComputeEngine {
69028
69937
  set recursionLimit(t) {
69029
69938
  this._runtimeState.recursionLimit = t;
69030
69939
  }
69940
+ /** Maximum number of elements a collection may have when materialized
69941
+ * (converted from a lazy form to a `List`). Default: 10,000.
69942
+ *
69943
+ * When a materialization would exceed this size, the operation leaves
69944
+ * the expression in its lazy form. Consumers can detect oversize
69945
+ * collections via the symbolic form's `count`.
69946
+ *
69947
+ * Set to `Infinity` (or `0` / a negative number) to disable the cap.
69948
+ *
69949
+ * @experimental
69950
+ */
69951
+ get maxCollectionSize() {
69952
+ return this._runtimeState.maxCollectionSize;
69953
+ }
69954
+ set maxCollectionSize(t) {
69955
+ this._runtimeState.maxCollectionSize = t;
69956
+ }
69031
69957
  /**
69032
69958
  * Flag to prevent infinite recursion in the verify/ask/equality checking cycle.
69033
69959
  *
@@ -69304,6 +70230,18 @@ var ComputeEngine = class _ComputeEngine {
69304
70230
  lookupDefinition(id) {
69305
70231
  return lookupDefinition(this, id);
69306
70232
  }
70233
+ normalizeIdentifier(latex) {
70234
+ if (!latex) return "";
70235
+ if (isValidSymbol(latex)) return latex;
70236
+ this.pushScope();
70237
+ try {
70238
+ const expr2 = this.parse(latex);
70239
+ if (isSymbol2(expr2)) return expr2.symbol;
70240
+ } finally {
70241
+ this.popScope();
70242
+ }
70243
+ return "";
70244
+ }
69307
70245
  operatorInfo(head) {
69308
70246
  const def = this.lookupDefinition(head);
69309
70247
  if (!def || !isOperatorDef(def)) return void 0;
@@ -69313,6 +70251,15 @@ var ComputeEngine = class _ComputeEngine {
69313
70251
  signature: op.signature
69314
70252
  };
69315
70253
  }
70254
+ symbolInfo(name) {
70255
+ const def = this.lookupDefinition(name);
70256
+ if (!def || !isValueDef(def)) return void 0;
70257
+ const v = def.value;
70258
+ return {
70259
+ kind: v.isConstant ? "constant" : "variable",
70260
+ type: v.type
70261
+ };
70262
+ }
69316
70263
  /**
69317
70264
  * Associate a new definition to a symbol in the current context.
69318
70265
  *
@@ -69765,7 +70712,7 @@ var ComputeEngine = class _ComputeEngine {
69765
70712
  _setDefaultEngineFactory(() => new ComputeEngine());
69766
70713
 
69767
70714
  // src/core.ts
69768
- var version = "0.57.0";
70715
+ var version = "0.58.0";
69769
70716
  export {
69770
70717
  ComputeEngine,
69771
70718
  N,