@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
@@ -1,4 +1,4 @@
1
- /** Compute Engine 0.57.0 */
1
+ /** Compute Engine 0.58.0 */
2
2
  (function(global,factory){typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'],factory):(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ComputeEngine = {}));})(this, (function (exports) { 'use strict';
3
3
  var ComputeEngine = (() => {
4
4
  var __defProp = Object.defineProperty;
@@ -4344,7 +4344,42 @@ var ComputeEngine = (() => {
4344
4344
  if (b === "nothing") return a;
4345
4345
  if (isSubtype(a, b)) return b;
4346
4346
  if (isSubtype(b, a)) return a;
4347
- return superType(a, b);
4347
+ const sup = superType(a, b);
4348
+ if (LOSSY_SUPERTYPE.has(sup)) return unionTypes(a, b);
4349
+ return sup;
4350
+ }
4351
+ var LOSSY_SUPERTYPE = /* @__PURE__ */ new Set([
4352
+ "scalar",
4353
+ "value",
4354
+ "function",
4355
+ "expression",
4356
+ "collection",
4357
+ "indexed_collection",
4358
+ "list",
4359
+ "set",
4360
+ "tuple",
4361
+ "record",
4362
+ "dictionary",
4363
+ "map",
4364
+ "any"
4365
+ ]);
4366
+ function unionTypes(a, b) {
4367
+ const members = [];
4368
+ const push = (t) => {
4369
+ if (typeof t === "object" && t.kind === "union") {
4370
+ for (const m of t.types) push(m);
4371
+ return;
4372
+ }
4373
+ const key = typeof t === "string" ? t : JSON.stringify(t);
4374
+ if (!members.some(
4375
+ (m) => (typeof m === "string" ? m : JSON.stringify(m)) === key
4376
+ ))
4377
+ members.push(t);
4378
+ };
4379
+ push(a);
4380
+ push(b);
4381
+ if (members.length === 1) return members[0];
4382
+ return { kind: "union", types: members };
4348
4383
  }
4349
4384
  function narrow(...types) {
4350
4385
  if (types.length === 0) return "nothing";
@@ -4422,7 +4457,7 @@ var ComputeEngine = (() => {
4422
4457
  if (type2.kind === "set") return type2.elements;
4423
4458
  if (type2.kind === "tuple") return widen(...type2.elements.map((x) => x.type));
4424
4459
  if (type2.kind === "dictionary")
4425
- return parseType(`tuple<string, ${type2.values}>`);
4460
+ return parseType(`tuple<string, ${typeToString(type2.values)}>`);
4426
4461
  if (type2.kind === "record") {
4427
4462
  return parseType(
4428
4463
  `tuple<string, ${typeToString(widen(...Object.values(type2.elements)))}>`
@@ -5968,6 +6003,84 @@ var ComputeEngine = (() => {
5968
6003
  }
5969
6004
 
5970
6005
  // src/compute-engine/boxed-expression/inequality-bounds.ts
6006
+ function extractIntervalBounds(expr2, symbol2) {
6007
+ if (isFunction2(expr2, "When")) {
6008
+ const cond = expr2.op2;
6009
+ if (!cond) return void 0;
6010
+ return extractIntervalBounds(cond, symbol2);
6011
+ }
6012
+ if (isFunction2(expr2, "Multiply")) {
6013
+ const ops = expr2.ops;
6014
+ if (!ops) return void 0;
6015
+ const merged = {};
6016
+ for (const sub2 of ops) {
6017
+ if (isFunction2(sub2, "When")) {
6018
+ const sub_ = extractIntervalBounds(sub2, symbol2);
6019
+ if (sub_ !== void 0) _mergeBounds(merged, sub_);
6020
+ }
6021
+ }
6022
+ return _hasAnyBound(merged) ? merged : void 0;
6023
+ }
6024
+ const result = {};
6025
+ if (isFunction2(expr2, "And")) {
6026
+ const ops = expr2.ops;
6027
+ if (!ops) return void 0;
6028
+ for (const sub2 of ops) {
6029
+ const subBounds = extractIntervalBounds(sub2, symbol2);
6030
+ if (subBounds === void 0) continue;
6031
+ _mergeBounds(result, subBounds);
6032
+ }
6033
+ return _hasAnyBound(result) ? result : void 0;
6034
+ }
6035
+ const op = expr2.operator;
6036
+ if ((op === "Less" || op === "LessEqual" || op === "Greater" || op === "GreaterEqual") && isFunction2(expr2)) {
6037
+ const isStrict = op === "Less" || op === "Greater";
6038
+ const ops = expr2.ops;
6039
+ if (!ops || ops.length < 2) return void 0;
6040
+ const flipped = op === "Greater" || op === "GreaterEqual" ? [...ops].reverse() : ops;
6041
+ for (let i = 0; i < flipped.length; i++) {
6042
+ if (isSymbol2(flipped[i], symbol2)) {
6043
+ if (i > 0) {
6044
+ const candidate = flipped[i - 1];
6045
+ if (result.lower === void 0 || candidate.isGreater(result.lower) === true) {
6046
+ result.lower = candidate;
6047
+ result.lowerStrict = isStrict;
6048
+ }
6049
+ }
6050
+ if (i < flipped.length - 1) {
6051
+ const candidate = flipped[i + 1];
6052
+ if (result.upper === void 0 || candidate.isLess(result.upper) === true) {
6053
+ result.upper = candidate;
6054
+ result.upperStrict = isStrict;
6055
+ }
6056
+ }
6057
+ }
6058
+ }
6059
+ return _hasAnyBound(result) ? result : void 0;
6060
+ }
6061
+ return void 0;
6062
+ }
6063
+ function _mergeBounds(into, from) {
6064
+ if (from.lower !== void 0) {
6065
+ if (into.lower === void 0 || from.lower.isGreater(into.lower) === true) {
6066
+ into.lower = from.lower;
6067
+ into.lowerStrict = from.lowerStrict;
6068
+ } else if (from.lower.isSame(into.lower)) {
6069
+ into.lowerStrict = into.lowerStrict || from.lowerStrict;
6070
+ }
6071
+ }
6072
+ if (from.upper !== void 0) {
6073
+ if (into.upper === void 0 || from.upper.isLess(into.upper) === true) {
6074
+ into.upper = from.upper;
6075
+ into.upperStrict = from.upperStrict;
6076
+ } else if (from.upper.isSame(into.upper)) {
6077
+ into.upperStrict = into.upperStrict || from.upperStrict;
6078
+ }
6079
+ }
6080
+ }
6081
+ function _hasAnyBound(b) {
6082
+ return b.lower !== void 0 || b.upper !== void 0;
6083
+ }
5971
6084
  function getInequalityBoundsFromAssumptions(ce, symbol2) {
5972
6085
  const result = {};
5973
6086
  const assumptions = ce.context?.assumptions;
@@ -5984,8 +6097,8 @@ var ComputeEngine = (() => {
5984
6097
  const isStrict = op === "Less";
5985
6098
  if (isFunction2(lhs, "Negate") && isSymbol2(lhs.op1, symbol2)) {
5986
6099
  const bound = ce.Zero;
5987
- if (result.lowerBound === void 0 || bound.isGreater(result.lowerBound) === true) {
5988
- result.lowerBound = bound;
6100
+ if (result.lower === void 0 || bound.isGreater(result.lower) === true) {
6101
+ result.lower = bound;
5989
6102
  result.lowerStrict = isStrict;
5990
6103
  }
5991
6104
  }
@@ -6004,16 +6117,16 @@ var ComputeEngine = (() => {
6004
6117
  }
6005
6118
  if (hasNegatedSymbol && constantSum !== 0) {
6006
6119
  const bound = ce.expr(constantSum);
6007
- if (result.lowerBound === void 0 || bound.isGreater(result.lowerBound) === true) {
6008
- result.lowerBound = bound;
6120
+ if (result.lower === void 0 || bound.isGreater(result.lower) === true) {
6121
+ result.lower = bound;
6009
6122
  result.lowerStrict = isStrict;
6010
6123
  }
6011
6124
  }
6012
6125
  }
6013
6126
  if (isSymbol2(lhs, symbol2)) {
6014
6127
  const bound = ce.Zero;
6015
- if (result.upperBound === void 0 || bound.isLess(result.upperBound) === true) {
6016
- result.upperBound = bound;
6128
+ if (result.upper === void 0 || bound.isLess(result.upper) === true) {
6129
+ result.upper = bound;
6017
6130
  result.upperStrict = isStrict;
6018
6131
  }
6019
6132
  }
@@ -6032,8 +6145,8 @@ var ComputeEngine = (() => {
6032
6145
  }
6033
6146
  if (hasSymbol && constantSum !== 0) {
6034
6147
  const bound = ce.expr(-constantSum);
6035
- if (result.upperBound === void 0 || bound.isLess(result.upperBound) === true) {
6036
- result.upperBound = bound;
6148
+ if (result.upper === void 0 || bound.isLess(result.upper) === true) {
6149
+ result.upper = bound;
6037
6150
  result.upperStrict = isStrict;
6038
6151
  }
6039
6152
  }
@@ -6253,8 +6366,8 @@ var ComputeEngine = (() => {
6253
6366
  const bounds = getInequalityBoundsFromAssumptions(a.engine, b.symbol);
6254
6367
  const aNum = typeof a.numericValue === "number" ? a.numericValue : a.numericValue.re;
6255
6368
  if (aNum !== void 0 && Number.isFinite(aNum)) {
6256
- if (bounds.lowerBound !== void 0) {
6257
- const lb = bounds.lowerBound;
6369
+ if (bounds.lower !== void 0) {
6370
+ const lb = bounds.lower;
6258
6371
  const lowerNum = isNumber(lb) ? typeof lb.numericValue === "number" ? lb.numericValue : lb.numericValue.re : void 0;
6259
6372
  if (lowerNum !== void 0 && Number.isFinite(lowerNum)) {
6260
6373
  if (lowerNum > aNum) return "<";
@@ -6262,8 +6375,8 @@ var ComputeEngine = (() => {
6262
6375
  if (lowerNum === aNum && !bounds.lowerStrict) return "<=";
6263
6376
  }
6264
6377
  }
6265
- if (bounds.upperBound !== void 0) {
6266
- const ub = bounds.upperBound;
6378
+ if (bounds.upper !== void 0) {
6379
+ const ub = bounds.upper;
6267
6380
  const upperNum = isNumber(ub) ? typeof ub.numericValue === "number" ? ub.numericValue : ub.numericValue.re : void 0;
6268
6381
  if (upperNum !== void 0 && Number.isFinite(upperNum)) {
6269
6382
  if (upperNum < aNum) return ">";
@@ -6293,8 +6406,8 @@ var ComputeEngine = (() => {
6293
6406
  if (typeof b === "number") {
6294
6407
  if (isSymbol2(a)) {
6295
6408
  const bounds = getInequalityBoundsFromAssumptions(a.engine, a.symbol);
6296
- if (bounds.lowerBound !== void 0) {
6297
- const lb = bounds.lowerBound;
6409
+ if (bounds.lower !== void 0) {
6410
+ const lb = bounds.lower;
6298
6411
  const lowerNum = isNumber(lb) ? typeof lb.numericValue === "number" ? lb.numericValue : lb.numericValue.re : void 0;
6299
6412
  if (lowerNum !== void 0 && Number.isFinite(lowerNum)) {
6300
6413
  if (lowerNum > b) return ">";
@@ -6302,8 +6415,8 @@ var ComputeEngine = (() => {
6302
6415
  if (lowerNum === b && !bounds.lowerStrict) return ">=";
6303
6416
  }
6304
6417
  }
6305
- if (bounds.upperBound !== void 0) {
6306
- const ub = bounds.upperBound;
6418
+ if (bounds.upper !== void 0) {
6419
+ const ub = bounds.upper;
6307
6420
  const upperNum = isNumber(ub) ? typeof ub.numericValue === "number" ? ub.numericValue : ub.numericValue.re : void 0;
6308
6421
  if (upperNum !== void 0 && Number.isFinite(upperNum)) {
6309
6422
  if (upperNum < b) return "<";
@@ -6359,8 +6472,8 @@ var ComputeEngine = (() => {
6359
6472
  const bounds = getInequalityBoundsFromAssumptions(a.engine, a.symbol);
6360
6473
  const bNum = typeof b.numericValue === "number" ? b.numericValue : b.numericValue.re;
6361
6474
  if (bNum !== void 0 && Number.isFinite(bNum)) {
6362
- if (bounds.lowerBound !== void 0) {
6363
- const lb = bounds.lowerBound;
6475
+ if (bounds.lower !== void 0) {
6476
+ const lb = bounds.lower;
6364
6477
  const lowerNum = isNumber(lb) ? typeof lb.numericValue === "number" ? lb.numericValue : lb.numericValue.re : void 0;
6365
6478
  if (lowerNum !== void 0 && Number.isFinite(lowerNum)) {
6366
6479
  if (lowerNum > bNum) return ">";
@@ -6368,8 +6481,8 @@ var ComputeEngine = (() => {
6368
6481
  if (lowerNum === bNum && !bounds.lowerStrict) return ">=";
6369
6482
  }
6370
6483
  }
6371
- if (bounds.upperBound !== void 0) {
6372
- const ub = bounds.upperBound;
6484
+ if (bounds.upper !== void 0) {
6485
+ const ub = bounds.upper;
6373
6486
  const upperNum = isNumber(ub) ? typeof ub.numericValue === "number" ? ub.numericValue : ub.numericValue.re : void 0;
6374
6487
  if (upperNum !== void 0 && Number.isFinite(upperNum)) {
6375
6488
  if (upperNum < bNum) return "<";
@@ -6907,6 +7020,12 @@ var ComputeEngine = (() => {
6907
7020
  scoped = false;
6908
7021
  signature;
6909
7022
  inferredSignature = true;
7023
+ /** True if this operator definition was created from a user-defined
7024
+ * function literal (e.g. via `ce.assign('f', ce.parse('x \\mapsto x^2'))`).
7025
+ * Used to enable auto-broadcasting when applied to indexed collections.
7026
+ * @internal
7027
+ */
7028
+ _isLambda = false;
6910
7029
  type;
6911
7030
  sgn;
6912
7031
  eq;
@@ -7064,6 +7183,8 @@ var ComputeEngine = (() => {
7064
7183
  this.engine._typeResolver
7065
7184
  );
7066
7185
  }
7186
+ if (isFunction2(boxedFn) && boxedFn.operator === "Function")
7187
+ this._isLambda = true;
7067
7188
  const fn = applicable(boxedFn);
7068
7189
  evaluate2 = (xs, _options) => fn(xs);
7069
7190
  Object.defineProperty(evaluate2, "toString", {
@@ -8380,6 +8501,29 @@ var ComputeEngine = (() => {
8380
8501
  get isReal() {
8381
8502
  return void 0;
8382
8503
  }
8504
+ toSignedFunction() {
8505
+ const op = this.operator;
8506
+ if (op === void 0 || this.ops === void 0 || this.ops.length < 2) {
8507
+ return void 0;
8508
+ }
8509
+ const [lhs, rhs] = this.ops;
8510
+ const engine = this.engine;
8511
+ switch (op) {
8512
+ case "Equal":
8513
+ case "NotEqual":
8514
+ case "Less":
8515
+ case "LessEqual":
8516
+ return engine.function("Subtract", [lhs, rhs]);
8517
+ case "Greater":
8518
+ case "GreaterEqual":
8519
+ return engine.function("Subtract", [rhs, lhs]);
8520
+ default:
8521
+ return void 0;
8522
+ }
8523
+ }
8524
+ getInterval(symbol2) {
8525
+ return extractIntervalBounds(this, symbol2);
8526
+ }
8383
8527
  simplify(_options) {
8384
8528
  return this;
8385
8529
  }
@@ -10398,15 +10542,16 @@ var ComputeEngine = (() => {
10398
10542
  precedence: ASSIGNMENT_PRECEDENCE,
10399
10543
  parse: parseAssign
10400
10544
  },
10401
- // General colon operator (type annotation, mapping notation)
10402
- // Precedence below assignment (260) so `:=` takes priority,
10403
- // and below arrows (270) so `f: A \to B` parses as `Colon(f, To(A, B))`
10545
+ // General colon operator (type annotation, mapping notation, Desmos piecewise)
10546
+ // Precedence below comparisons (245) so `cond : val` (Desmos compact piecewise)
10547
+ // parses as `Colon(cond, val)`, and below arrows (270) so
10548
+ // `f: A \to B` parses as `Colon(f, To(A, B))`.
10404
10549
  {
10405
10550
  name: "Colon",
10406
10551
  latexTrigger: ":",
10407
10552
  kind: "infix",
10408
10553
  associativity: "right",
10409
- precedence: 250,
10554
+ precedence: 240,
10410
10555
  serialize: (serializer, expr2) => joinLatex([
10411
10556
  serializer.serialize(operand(expr2, 1)),
10412
10557
  "\\colon",
@@ -10417,7 +10562,7 @@ var ComputeEngine = (() => {
10417
10562
  latexTrigger: "\\colon",
10418
10563
  kind: "infix",
10419
10564
  associativity: "right",
10420
- precedence: 250,
10565
+ precedence: 240,
10421
10566
  parse: "Colon"
10422
10567
  },
10423
10568
  {
@@ -11987,7 +12132,10 @@ var ComputeEngine = (() => {
11987
12132
  p.skipVisualSpace();
11988
12133
  const isComma = p.peek === ",";
11989
12134
  p.index = saved;
11990
- return isComma;
12135
+ if (isComma) return true;
12136
+ if (peekKeyword(p, "where")) return true;
12137
+ if (peekKeyword(p, "with")) return true;
12138
+ return false;
11991
12139
  }
11992
12140
  };
11993
12141
  const elements = [];
@@ -12028,6 +12176,25 @@ var ComputeEngine = (() => {
12028
12176
  parser.skipVisualSpace();
12029
12177
  } while (parser.match(","));
12030
12178
  if (bindings.length === 0) return null;
12179
+ const forStart = parser.index;
12180
+ if (matchKeyword(parser, "for")) {
12181
+ const loop = parseForComprehension(parser, lhs, until);
12182
+ if (loop) {
12183
+ const block2 = [];
12184
+ for (const b of bindings) {
12185
+ const normalized = normalizeLocalAssign(b);
12186
+ if (operator(normalized) === "Assign") {
12187
+ block2.push(["Declare", operand(normalized, 1)]);
12188
+ block2.push(normalized);
12189
+ } else {
12190
+ block2.push(normalized);
12191
+ }
12192
+ }
12193
+ block2.push(loop);
12194
+ return ["Block", ...block2];
12195
+ }
12196
+ parser.index = forStart;
12197
+ }
12031
12198
  const block = [];
12032
12199
  for (const b of bindings) {
12033
12200
  const normalized = normalizeLocalAssign(b);
@@ -12241,6 +12408,17 @@ var ComputeEngine = (() => {
12241
12408
  const upperExpr = openRight ? ["Open", upper] : upper;
12242
12409
  return ["Interval", lowerExpr, upperExpr];
12243
12410
  }
12411
+ var COMPARISON_HEADS = /* @__PURE__ */ new Set([
12412
+ "Less",
12413
+ "LessEqual",
12414
+ "Greater",
12415
+ "GreaterEqual",
12416
+ "Equal",
12417
+ "NotEqual",
12418
+ "And",
12419
+ "Or",
12420
+ "Not"
12421
+ ]);
12244
12422
  var DEFINITIONS_SETS = [
12245
12423
  //
12246
12424
  // Constants
@@ -12499,18 +12677,58 @@ var ComputeEngine = (() => {
12499
12677
  closeTrigger: "}",
12500
12678
  parse: (_parser, body) => {
12501
12679
  if (isEmptySequence(body)) return "EmptySet";
12680
+ if (operator(body) == "Delimiter" && stringValue(operand(body, 2)) === ",") {
12681
+ body = operand(body, 1);
12682
+ }
12502
12683
  const h = operator(body);
12503
- if (h === "Divides" || h === "Colon") {
12684
+ if (h === "Divides") {
12504
12685
  const expr2 = operand(body, 1);
12505
12686
  const condition = operand(body, 2);
12506
12687
  if (expr2 !== null && condition !== null)
12507
12688
  return ["Set", expr2, ["Condition", condition]];
12508
12689
  }
12509
- if (operator(body) == "Delimiter" && stringValue(operand(body, 2)) === ",") {
12510
- body = operand(body, 1);
12690
+ if (h === "Colon") {
12691
+ const lhs = operand(body, 1);
12692
+ const rhs = operand(body, 2);
12693
+ if (lhs !== null && rhs !== null) {
12694
+ const lhsOp = operator(lhs);
12695
+ if (lhsOp !== null && COMPARISON_HEADS.has(lhsOp)) {
12696
+ return ["Which", lhs, rhs];
12697
+ }
12698
+ return ["Set", lhs, ["Condition", rhs]];
12699
+ }
12511
12700
  }
12512
- if (operator(body) !== "Sequence") return ["Set", body];
12513
- return ["Set", ...operands(body)];
12701
+ if (h === "Sequence") {
12702
+ const elements = operands(body);
12703
+ const colonElements = elements.filter((el) => operator(el) === "Colon");
12704
+ const allPiecewise = colonElements.length > 0 && colonElements.every((el) => {
12705
+ const lhs = operand(el, 1);
12706
+ const lhsOp = lhs !== null ? operator(lhs) : null;
12707
+ return lhsOp !== null && COMPARISON_HEADS.has(lhsOp);
12708
+ });
12709
+ if (allPiecewise) {
12710
+ const whichOps = [];
12711
+ for (let i = 0; i < elements.length; i++) {
12712
+ const el = elements[i];
12713
+ if (operator(el) === "Colon") {
12714
+ const cond = operand(el, 1);
12715
+ const val = operand(el, 2);
12716
+ if (cond === null || val === null) {
12717
+ return ["Set", ...elements];
12718
+ }
12719
+ whichOps.push(cond, val);
12720
+ } else {
12721
+ if (i !== elements.length - 1) {
12722
+ return ["Set", ...elements];
12723
+ }
12724
+ whichOps.push("True", el);
12725
+ }
12726
+ }
12727
+ return ["Which", ...whichOps];
12728
+ }
12729
+ return ["Set", ...elements];
12730
+ }
12731
+ return ["Set", body];
12514
12732
  },
12515
12733
  serialize: (serializer, expr2) => {
12516
12734
  if (nops(expr2) === 2 && operator(operand(expr2, 2)) === "Condition") {
@@ -14514,7 +14732,8 @@ var ComputeEngine = (() => {
14514
14732
  minPrec: MULTIPLICATION_PRECEDENCE,
14515
14733
  condition: (parser2) => trigCommands[parser2.peek] || (until?.condition?.(parser2) ?? false)
14516
14734
  });
14517
- const appliedFn = args === null ? fn : typeof fn === "string" ? [fn, ...args] : ["Apply", fn, ...args];
14735
+ const head = fn === "Arctan" && args?.length === 2 ? "Arctan2" : fn;
14736
+ const appliedFn = args === null ? fn : typeof head === "string" ? [head, ...args] : ["Apply", head, ...args];
14518
14737
  return sup === null ? appliedFn : ["Power", appliedFn, sup];
14519
14738
  };
14520
14739
  }
@@ -16730,10 +16949,17 @@ var ComputeEngine = (() => {
16730
16949
  // The capitalized library entries already exist; these are pure parse
16731
16950
  // aliases so the lowercase names don't land in `unsupported-operator`.
16732
16951
  // ---------------------------------------------------------------------------
16952
+ { latexTrigger: "\\operatorname{count}", parse: "Length" },
16733
16953
  { latexTrigger: "\\operatorname{random}", parse: "Random" },
16734
16954
  { latexTrigger: "\\operatorname{shuffle}", parse: "Shuffle" },
16735
16955
  { latexTrigger: "\\operatorname{repeat}", parse: "Repeat" },
16736
16956
  { latexTrigger: "\\operatorname{join}", parse: "Join" },
16957
+ { latexTrigger: "\\operatorname{range}", parse: "Range" },
16958
+ // Note: `\operatorname{with}` (Desmos's local-binding clause) is intentionally
16959
+ // NOT registered here. Use the math-notation equivalent `\operatorname{where}`
16960
+ // (with `\coloneq` for bindings), or register `with` as a custom dictionary
16961
+ // entry at the integration layer — see the "Desmos-Specific Syntax — Prefer
16962
+ // Custom LaTeX Dictionary" section in COMPUTE_ENGINE.md for a worked example.
16737
16963
  // ---------------------------------------------------------------------------
16738
16964
  // Geometric primitive heads. Registered as known typed heads so consumers
16739
16965
  // can branch on the operator name; CE itself doesn't render them. The
@@ -22575,6 +22801,15 @@ var ComputeEngine = (() => {
22575
22801
  }
22576
22802
  } else {
22577
22803
  for (const item of t) {
22804
+ const op = item.operator;
22805
+ if (op === "Tuple" || op === "Pair" || op === "Single" || op === "Triple" || op === "Quadruple" || op === "KeyValuePair" || op === "Dictionary" || op === "Set" || op === "Record") {
22806
+ valid = false;
22807
+ return;
22808
+ }
22809
+ if (item.type.type === "string") {
22810
+ valid = false;
22811
+ return;
22812
+ }
22578
22813
  dtype = getSupertype(dtype, getExpressionDatatype(item));
22579
22814
  }
22580
22815
  }
@@ -27610,6 +27845,15 @@ ${lines.join("\n")}`;
27610
27845
  return void 0;
27611
27846
  }
27612
27847
 
27848
+ // src/compute-engine/numerics/random.ts
27849
+ function deterministicRandom(seed) {
27850
+ const v = Math.sin(seed * 12.9898) * 43758.5453;
27851
+ return v - Math.floor(v);
27852
+ }
27853
+ function nextSeed(seed) {
27854
+ return seed + 0.6180339887498949;
27855
+ }
27856
+
27613
27857
  // src/compute-engine/boxed-expression/canonical-utils.ts
27614
27858
  function canonical(ce, xs, scope) {
27615
27859
  if (xs.every((x) => x.isCanonical)) return xs;
@@ -27659,6 +27903,19 @@ ${lines.join("\n")}`;
27659
27903
  indexWhere: void 0
27660
27904
  }
27661
27905
  },
27906
+ Length: {
27907
+ description: "Number of elements in a collection. Returns undefined for non-collections and for infinite collections.",
27908
+ complexity: 4e3,
27909
+ signature: "(any) -> integer",
27910
+ type: () => "integer",
27911
+ evaluate: ([xs], { engine }) => {
27912
+ if (!xs.isCollection) return void 0;
27913
+ if (xs.isEmptyCollection) return engine.Zero;
27914
+ const n = xs.count;
27915
+ if (n === void 0 || !isFinite(n)) return void 0;
27916
+ return engine.number(n);
27917
+ }
27918
+ },
27662
27919
  Tuple: {
27663
27920
  description: "A fixed number of heterogeneous elements",
27664
27921
  complexity: 8200,
@@ -27912,10 +28169,12 @@ ${lines.join("\n")}`;
27912
28169
  const upper = expr2.op2.re;
27913
28170
  let count = expr2.op3.re;
27914
28171
  if (!isFinite(count)) count = DEFAULT_LINSPACE_COUNT;
28172
+ count = Math.floor(count);
27915
28173
  if (!isFinite(lower) || !isFinite(upper)) return void 0;
27916
28174
  if (index < 1 || index > count) return void 0;
28175
+ if (count === 1) return expr2.engine.number(lower);
27917
28176
  return expr2.engine.number(
27918
- lower + (upper - lower) * (index - 1) / count
28177
+ lower + (upper - lower) * (index - 1) / (count - 1)
27919
28178
  );
27920
28179
  },
27921
28180
  iterator: (expr2) => {
@@ -27934,6 +28193,8 @@ ${lines.join("\n")}`;
27934
28193
  !isFinite(expr2.op3.re) ? DEFAULT_LINSPACE_COUNT : expr2.op3.re
27935
28194
  );
27936
28195
  }
28196
+ totalCount = Math.floor(totalCount);
28197
+ const denom = totalCount > 1 ? totalCount - 1 : 1;
27937
28198
  let index = 1;
27938
28199
  return {
27939
28200
  next: () => {
@@ -27942,7 +28203,7 @@ ${lines.join("\n")}`;
27942
28203
  index += 1;
27943
28204
  return {
27944
28205
  value: expr2.engine.number(
27945
- lower + (upper - lower) * (index - 1 - 1) / totalCount
28206
+ lower + (upper - lower) * (index - 1 - 1) / denom
27946
28207
  ),
27947
28208
  done: false
27948
28209
  };
@@ -27958,9 +28219,14 @@ ${lines.join("\n")}`;
27958
28219
  if (t < lower || t > upper) return false;
27959
28220
  let count = expr2.op3.re;
27960
28221
  if (!isFinite(count)) count = DEFAULT_LINSPACE_COUNT;
28222
+ count = Math.floor(count);
27961
28223
  if (count === 0) return false;
27962
- const step = (upper - lower) / count;
27963
- return (t - lower) % step === 0;
28224
+ if (count === 1) return t === lower;
28225
+ const step = (upper - lower) / (count - 1);
28226
+ const k = (t - lower) / step;
28227
+ const tol = expr2.engine.tolerance;
28228
+ const kRounded = Math.round(k);
28229
+ return kRounded >= 0 && kRounded <= count - 1 && Math.abs(k - kRounded) < tol;
27964
28230
  }
27965
28231
  }
27966
28232
  },
@@ -28285,10 +28551,12 @@ ${lines.join("\n")}`;
28285
28551
  description: [
28286
28552
  "Access an element of an indexed collection.",
28287
28553
  "If the index is negative, it is counted from the end.",
28288
- "Multiple indices can be provided to access nested collections (e.g., matrices)."
28554
+ "Multiple indices can be provided to access nested collections (e.g., matrices).",
28555
+ "If the index is a finite collection of booleans, returns the elements where the mask is True.",
28556
+ "If the index is a finite collection of integers, returns the elements at those indices."
28289
28557
  ],
28290
28558
  complexity: 8200,
28291
- signature: "(value: indexed_collection, index: (number|string)+) -> unknown",
28559
+ signature: "(value: indexed_collection, index: (number|string|indexed_collection)+) -> unknown",
28292
28560
  type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? collectionElementType(xs.type.type) ?? "any",
28293
28561
  evaluate: (ops, { engine: ce }) => {
28294
28562
  let expr2 = ops[0];
@@ -28299,12 +28567,39 @@ ${lines.join("\n")}`;
28299
28567
  if (!at) return void 0;
28300
28568
  const opAtIndex = ops[index];
28301
28569
  const s = isString(opAtIndex) ? opAtIndex.string : void 0;
28302
- if (s !== void 0) expr2 = at(expr2, s) ?? ce.Nothing;
28303
- else {
28304
- const i = ops[index].re;
28305
- if (!Number.isInteger(i)) return void 0;
28306
- expr2 = at(expr2, i) ?? ce.Nothing;
28570
+ if (s !== void 0) {
28571
+ expr2 = at(expr2, s) ?? ce.Nothing;
28572
+ index += 1;
28573
+ continue;
28574
+ }
28575
+ if (opAtIndex.isCollection && opAtIndex.isFiniteCollection) {
28576
+ const indices = Array.from(opAtIndex.each());
28577
+ const isMask = indices.every((m) => {
28578
+ const name = sym(m);
28579
+ return name === "True" || name === "False";
28580
+ });
28581
+ const picked = [];
28582
+ if (isMask) {
28583
+ indices.forEach((m, i2) => {
28584
+ if (sym(m) !== "True") return;
28585
+ const v = at(expr2, i2 + 1);
28586
+ if (v !== void 0) picked.push(v);
28587
+ });
28588
+ } else {
28589
+ for (const m of indices) {
28590
+ const k = m.re;
28591
+ if (!Number.isInteger(k)) return void 0;
28592
+ const v = at(expr2, k);
28593
+ if (v !== void 0) picked.push(v);
28594
+ }
28595
+ }
28596
+ expr2 = ce._fn("List", picked);
28597
+ index += 1;
28598
+ continue;
28307
28599
  }
28600
+ const i = opAtIndex.re;
28601
+ if (!Number.isInteger(i)) return void 0;
28602
+ expr2 = at(expr2, i) ?? ce.Nothing;
28308
28603
  index += 1;
28309
28604
  }
28310
28605
  return expr2;
@@ -28315,7 +28610,7 @@ ${lines.join("\n")}`;
28315
28610
  description: ["Return `n` elements from a collection."],
28316
28611
  complexity: 8200,
28317
28612
  signature: "(xs: indexed_collection, count: number) -> indexed_collection",
28318
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
28613
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
28319
28614
  evaluate: (ops, { engine, materialization: eager }) => {
28320
28615
  if (!eager) return void 0;
28321
28616
  const takeExpr = engine._fn("Take", ops);
@@ -28362,7 +28657,7 @@ ${lines.join("\n")}`;
28362
28657
  description: ["Return the collection without the first n elements."],
28363
28658
  complexity: 8200,
28364
28659
  signature: "(xs: indexed_collection, count: number) -> indexed_collection",
28365
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
28660
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
28366
28661
  collection: {
28367
28662
  isLazy: (_expr) => true,
28368
28663
  count: (expr2) => {
@@ -28558,7 +28853,9 @@ ${lines.join("\n")}`;
28558
28853
  ],
28559
28854
  complexity: 8200,
28560
28855
  signature: "(value: indexed_collection, start: number, end: number) -> list",
28561
- type: ([xs]) => parseType(`list<${collectionElementType(xs.type.type)}>`),
28856
+ type: ([xs]) => parseType(
28857
+ `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`
28858
+ ),
28562
28859
  collection: {
28563
28860
  isLazy: (_expr) => true,
28564
28861
  count: (expr2) => {
@@ -28890,16 +29187,26 @@ ${lines.join("\n")}`;
28890
29187
  },
28891
29188
  // Randomize the order of the elements in the collection.
28892
29189
  Shuffle: {
28893
- description: "Randomize the order of the elements in the collection.",
29190
+ description: "Randomize the order of the elements in the collection. With an optional `seed` argument, the shuffle is deterministic.",
28894
29191
  complexity: 8200,
28895
- signature: "(indexed_collection) -> indexed_collection",
29192
+ signature: "(indexed_collection, real?) -> indexed_collection",
28896
29193
  type: (ops) => ops[0].type,
28897
- evaluate: ([xs], { engine: ce }) => {
29194
+ evaluate: ([xs, seedOp], { engine: ce }) => {
28898
29195
  if (!xs.isFiniteCollection) return void 0;
28899
29196
  const data = Array.from(xs.each());
28900
- for (let i = data.length - 1; i > 0; i--) {
28901
- const j = Math.floor(Math.random() * (i + 1));
28902
- [data[i], data[j]] = [data[j], data[i]];
29197
+ const seed = seedOp?.re;
29198
+ if (seed !== void 0 && !Number.isNaN(seed)) {
29199
+ let s = seed;
29200
+ for (let i = data.length - 1; i > 0; i--) {
29201
+ const j = Math.floor(deterministicRandom(s) * (i + 1));
29202
+ [data[i], data[j]] = [data[j], data[i]];
29203
+ s = nextSeed(s);
29204
+ }
29205
+ } else {
29206
+ for (let i = data.length - 1; i > 0; i--) {
29207
+ const j = Math.floor(Math.random() * (i + 1));
29208
+ [data[i], data[j]] = [data[j], data[i]];
29209
+ }
28903
29210
  }
28904
29211
  return ce.function(xs.operator, data);
28905
29212
  }
@@ -28966,7 +29273,9 @@ ${lines.join("\n")}`;
28966
29273
  if (t === "string")
28967
29274
  return parseType(`tuple<list<string>, list<integer>>`);
28968
29275
  return parseType(
28969
- `tuple<list<${collectionElementType(t)}>, list<integer>>`
29276
+ `tuple<list<${typeToString(
29277
+ collectionElementType(t) ?? "any"
29278
+ )}>, list<integer>>`
28970
29279
  );
28971
29280
  },
28972
29281
  evaluate: (ops, { engine: ce }) => {
@@ -28982,7 +29291,7 @@ ${lines.join("\n")}`;
28982
29291
  description: "Return a list of the unique elements of the collection.",
28983
29292
  complexity: 8200,
28984
29293
  signature: "(collection) -> list",
28985
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
29294
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
28986
29295
  evaluate: (ops, { engine: ce }) => {
28987
29296
  if (!ops[0].isFiniteCollection) return void 0;
28988
29297
  const [values, _counts] = tally(ops[0]);
@@ -28994,7 +29303,7 @@ ${lines.join("\n")}`;
28994
29303
  wikidata: "Q381060",
28995
29304
  complexity: 8200,
28996
29305
  signature: "(collection, integer | function) -> list",
28997
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
29306
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
28998
29307
  evaluate: ([xs, arg], { engine: ce }) => {
28999
29308
  if (!xs.isFiniteCollection) return void 0;
29000
29309
  const k = toInteger(arg);
@@ -29168,32 +29477,74 @@ ${lines.join("\n")}`;
29168
29477
  }
29169
29478
  }
29170
29479
  },
29171
- // Repeat(x) -> [x, x, ...]
29172
- // This is an infinite series. Can use Take(Repeat(x), n) to get a finite series
29173
- // x is evaluated once. Although could use Hold()?
29174
- // So that First(Repeat(Hold(Random(5))), 10) would return 10 random numbers...
29480
+ // Repeat(x) -> [x, x, ...] — infinite sequence
29481
+ // Repeat(x, n) -> [x, x, ..., x] — finite list of n copies
29175
29482
  Repeat: {
29176
- description: "Produce an infinite sequence by repeating a single value.",
29483
+ 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.",
29177
29484
  complexity: 8200,
29178
- signature: "(value: any) -> list",
29485
+ signature: "(value: any, count: integer?) -> list",
29486
+ evaluate: (ops, { engine }) => {
29487
+ if (ops.length !== 2) return void 0;
29488
+ const raw = toInteger(ops[1]);
29489
+ if (raw === null) return void 0;
29490
+ const n = Math.max(0, raw);
29491
+ if (n > engine.maxCollectionSize) return void 0;
29492
+ return engine._fn("List", Array(n).fill(ops[0]));
29493
+ },
29179
29494
  collection: {
29180
- isLazy: (_expr) => true,
29181
- count: () => Infinity,
29182
- isEmpty: (_expr) => false,
29183
- // Never empty
29184
- isFinite: () => false,
29185
- // Infinite collection
29495
+ isLazy: (expr2) => isFunction2(expr2) && expr2.ops?.length === 1,
29496
+ count: (expr2) => {
29497
+ if (!isFunction2(expr2)) return void 0;
29498
+ if (expr2.ops?.length === 2) {
29499
+ const n = toInteger(expr2.op2);
29500
+ return n !== null ? Math.max(0, n) : void 0;
29501
+ }
29502
+ return Infinity;
29503
+ },
29504
+ isEmpty: (expr2) => {
29505
+ if (!isFunction2(expr2)) return void 0;
29506
+ if (expr2.ops?.length === 2) {
29507
+ const n = toInteger(expr2.op2);
29508
+ return n !== null ? n <= 0 : void 0;
29509
+ }
29510
+ return false;
29511
+ },
29512
+ isFinite: (expr2) => isFunction2(expr2) && expr2.ops?.length === 2,
29186
29513
  contains: (expr2, target) => {
29187
29514
  if (!isFunction2(expr2)) return false;
29515
+ if (expr2.ops?.length === 2) {
29516
+ const n = toInteger(expr2.op2);
29517
+ if (n !== null && n <= 0) return false;
29518
+ }
29188
29519
  return expr2.op1.isSame(target);
29189
29520
  },
29190
29521
  iterator: (expr2) => {
29191
29522
  if (!isFunction2(expr2))
29192
29523
  return { next: () => ({ value: void 0, done: true }) };
29524
+ if (expr2.ops?.length === 2) {
29525
+ const n = toInteger(expr2.op2);
29526
+ if (n === null) {
29527
+ return { next: () => ({ value: void 0, done: true }) };
29528
+ }
29529
+ const count = Math.max(0, n);
29530
+ let i = 0;
29531
+ return {
29532
+ next: () => i++ < count ? { value: expr2.op1, done: false } : { value: void 0, done: true }
29533
+ };
29534
+ }
29193
29535
  return { next: () => ({ value: expr2.op1, done: false }) };
29194
29536
  },
29195
- at: (expr2, _index) => {
29537
+ // at is 1-based (consistent with Range, Take, and other collection handlers)
29538
+ at: (expr2, index) => {
29196
29539
  if (!isFunction2(expr2)) return void 0;
29540
+ if (typeof index !== "number") return void 0;
29541
+ if (expr2.ops?.length === 2) {
29542
+ const n = toInteger(expr2.op2);
29543
+ const count = n !== null ? Math.max(0, n) : 0;
29544
+ if (index < 1 || index > count) return void 0;
29545
+ } else {
29546
+ if (index < 1) return void 0;
29547
+ }
29197
29548
  return expr2.op1;
29198
29549
  }
29199
29550
  }
@@ -31479,11 +31830,12 @@ ${lines.join("\n")}`;
31479
31830
  );
31480
31831
  }
31481
31832
  },
31482
- // Complex: {
31483
- // // This function is converted during boxing, so unlikely to encounter
31484
- // wikidata: 'Q11567',
31485
- // complexity: 500,
31486
- // },
31833
+ Complex: {
31834
+ 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.',
31835
+ wikidata: "Q11567",
31836
+ complexity: 500,
31837
+ signature: "(real: number, imaginary: number) -> complex"
31838
+ },
31487
31839
  Divide: {
31488
31840
  description: "Quotient of a numerator and one or more denominators.",
31489
31841
  wikidata: "Q1226939",
@@ -32833,48 +33185,83 @@ ${lines.join("\n")}`;
32833
33185
  }
32834
33186
  },
32835
33187
  Sum: {
32836
- description: "`Sum(f, [a, b])` computes the sum of `f` from `a` to `b`",
33188
+ description: "`Sum(f, [a, b])` computes the sum of `f` from `a` to `b`; `Sum(L)` sums the elements of a collection `L`",
32837
33189
  wikidata: "Q218005",
32838
33190
  complexity: 1e3,
32839
33191
  broadcastable: false,
32840
33192
  scoped: true,
32841
33193
  lazy: true,
32842
- signature: "((number) -> number, bounds:tuple+) -> number",
32843
- canonical: ([body, ...bounds], { scope }) => canonicalBigop("Sum", body, bounds, scope),
32844
- evaluate: ([body, ...indexes], { engine, numericApproximation: numericApproximation2 }) => {
33194
+ signature: "(any, tuple*) -> number",
33195
+ canonical: ([body, ...bounds], { scope, engine: ce }) => {
33196
+ if (bounds.length === 0) {
33197
+ const canon = body?.canonical;
33198
+ if (canon?.isCollection) return ce._fn("Sum", [canon]);
33199
+ }
33200
+ return canonicalBigop("Sum", body, bounds, scope);
33201
+ },
33202
+ evaluate: ([first, ...rest], { engine, numericApproximation: numericApproximation2 }) => {
33203
+ if (rest.length === 0 && first?.isCollection) {
33204
+ if (first.isFiniteCollection !== true) return void 0;
33205
+ const result2 = run(
33206
+ reduceCollection2(
33207
+ first,
33208
+ engine.Zero,
33209
+ (acc, x) => acc.add(x.evaluate({ numericApproximation: numericApproximation2 }))
33210
+ ),
33211
+ engine._timeRemaining
33212
+ );
33213
+ return result2?.evaluate({ numericApproximation: numericApproximation2 }) ?? engine.NaN;
33214
+ }
32845
33215
  const result = run(
32846
33216
  reduceBigOp(
32847
- body,
32848
- indexes,
33217
+ first,
33218
+ rest,
32849
33219
  (acc, x) => acc.add(x.evaluate({ numericApproximation: numericApproximation2 })),
32850
33220
  engine.Zero
32851
33221
  ),
32852
33222
  engine._timeRemaining
32853
33223
  );
32854
- if (result === NON_ENUMERABLE_DOMAIN) {
32855
- return void 0;
32856
- }
33224
+ if (result === NON_ENUMERABLE_DOMAIN) return void 0;
32857
33225
  return result?.evaluate({ numericApproximation: numericApproximation2 }) ?? engine.NaN;
32858
33226
  },
32859
- evaluateAsync: async (xs, { engine, signal, numericApproximation: numericApproximation2 }) => {
33227
+ evaluateAsync: async ([first, ...rest], { engine, signal, numericApproximation: numericApproximation2 }) => {
33228
+ if (rest.length === 0 && first?.isCollection) {
33229
+ if (first.isFiniteCollection !== true) return void 0;
33230
+ const result2 = await runAsync(
33231
+ reduceCollection2(
33232
+ first,
33233
+ engine.Zero,
33234
+ (acc, x) => acc.add(x.evaluate({ numericApproximation: numericApproximation2 }))
33235
+ ),
33236
+ engine._timeRemaining,
33237
+ signal
33238
+ );
33239
+ return result2?.evaluate({ numericApproximation: numericApproximation2 }) ?? engine.NaN;
33240
+ }
32860
33241
  const result = await runAsync(
32861
33242
  reduceBigOp(
32862
- xs[0],
32863
- xs.slice(1),
33243
+ first,
33244
+ rest,
32864
33245
  (acc, x) => acc.add(x.evaluate({ numericApproximation: numericApproximation2 })),
32865
33246
  engine.Zero
32866
33247
  ),
32867
33248
  engine._timeRemaining,
32868
33249
  signal
32869
33250
  );
32870
- if (result === NON_ENUMERABLE_DOMAIN) {
32871
- return void 0;
32872
- }
33251
+ if (result === NON_ENUMERABLE_DOMAIN) return void 0;
32873
33252
  return result?.evaluate({ numericApproximation: numericApproximation2 }) ?? engine.NaN;
32874
33253
  }
32875
33254
  }
32876
33255
  }
32877
33256
  ];
33257
+ function* reduceCollection2(collection, init, combine) {
33258
+ let acc = init;
33259
+ for (const x of collection.each()) {
33260
+ acc = combine(acc, x);
33261
+ yield acc;
33262
+ }
33263
+ return acc;
33264
+ }
32878
33265
  function evaluateAbs(arg) {
32879
33266
  const ce = arg.engine;
32880
33267
  if (isNumber(arg)) {
@@ -43111,7 +43498,7 @@ ${e.message}
43111
43498
  var CONTROL_STRUCTURES_LIBRARY = [
43112
43499
  {
43113
43500
  Block: {
43114
- description: "Evaluate a sequence of expressions in a local scope.",
43501
+ 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.",
43115
43502
  lazy: true,
43116
43503
  scoped: true,
43117
43504
  signature: "(unknown*) -> unknown",
@@ -43173,7 +43560,7 @@ ${e.message}
43173
43560
  evaluateAsync: async (ops, { engine: ce, signal }) => runAsync(runLoop(ops[0], ops.slice(1), ce), ce._timeRemaining, signal)
43174
43561
  },
43175
43562
  When: {
43176
- description: "Conditional value: returns expr when cond holds, undefined otherwise.",
43563
+ 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.',
43177
43564
  lazy: true,
43178
43565
  signature: "(expression, boolean) -> any",
43179
43566
  type: ([expr2]) => expr2.type,
@@ -45032,7 +45419,7 @@ ${e.message}
45032
45419
  evaluate: (ops) => apply(ops[0], ops.slice(1))
45033
45420
  },
45034
45421
  Assign: {
45035
- description: "Assign a value to a symbol or define a sequence",
45422
+ 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).",
45036
45423
  lazy: true,
45037
45424
  pure: false,
45038
45425
  signature: "(symbol | expression, any) -> any",
@@ -45163,7 +45550,12 @@ ${e.message}
45163
45550
  evaluate: (ops, { engine: ce }) => {
45164
45551
  const symbolName2 = sym(ops[0].evaluate());
45165
45552
  if (!symbolName2) return void 0;
45553
+ const currentScope = ce.context.lexicalScope;
45554
+ const existing = currentScope.bindings.get(symbolName2);
45555
+ const existingValueDef = existing && isValueDef(existing) ? existing : void 0;
45556
+ const isAutoDeclareHere = !!existingValueDef && existingValueDef.value.inferredType && existingValueDef.value.value === void 0;
45166
45557
  if (!ops[1]) {
45558
+ if (isAutoDeclareHere) return ce.Nothing;
45167
45559
  ce.declare(symbolName2, { inferred: true, type: "unknown" });
45168
45560
  return ce.Nothing;
45169
45561
  }
@@ -45172,6 +45564,11 @@ ${e.message}
45172
45564
  (isString(t) ? t.string : void 0) ?? sym(t) ?? void 0
45173
45565
  );
45174
45566
  if (!isValidType(type2)) return void 0;
45567
+ if (isAutoDeclareHere && existingValueDef) {
45568
+ existingValueDef.value.type = ce.type(type2);
45569
+ existingValueDef.value.inferredType = false;
45570
+ return ce.Nothing;
45571
+ }
45175
45572
  ce.declare(symbolName2, type2);
45176
45573
  return ce.Nothing;
45177
45574
  }
@@ -45289,33 +45686,41 @@ ${e.message}
45289
45686
  },
45290
45687
  Random: {
45291
45688
  description: [
45292
- "Random(): Return a random number between 0 and 1",
45293
- "Random(n): Return a random integer between 0 and n-1",
45294
- "Random(m, n): Return a random integer between m and n-1"
45689
+ "Random(): non-deterministic float in [0, 1)",
45690
+ "Random(seed: real): deterministic float in [0, 1) from a real seed",
45691
+ "Random(n: integer): non-deterministic integer in [0, n)",
45692
+ "Random(m: integer, n: integer): non-deterministic integer in [m, n)"
45295
45693
  ],
45296
45694
  pure: false,
45297
- signature: "(lower:integer?, upper:integer?) -> finite_number",
45298
- type: ([lower, upper]) => {
45299
- if (lower === void 0 && upper === void 0) return "finite_number";
45300
- return "finite_integer";
45695
+ // Signature accepts: nothing, one number, or two integers.
45696
+ // Use `number` (not `integer`) for the single-arg case so float seeds
45697
+ // type-check; runtime dispatch differentiates integer vs real.
45698
+ signature: "(number?, integer?) -> finite_number",
45699
+ type: ([first, second]) => {
45700
+ if (first === void 0) return "finite_number";
45701
+ if (second !== void 0) return "finite_integer";
45702
+ if (first.type.matches("integer")) return "finite_integer";
45703
+ return "finite_number";
45301
45704
  },
45302
45705
  sgn: () => "non-negative",
45303
45706
  evaluate: (ops, { engine: ce }) => {
45304
45707
  if (ops.length === 0) return ce.number(Math.random());
45305
- const [lowerOp, upperOp] = ops;
45306
- let lower;
45307
- let upper;
45308
- if (upperOp === void 0) {
45309
- lower = 0;
45310
- upper = Math.floor(lowerOp.re - 1);
45311
- if (isNaN(upper)) upper = 0;
45312
- } else {
45313
- lower = Math.floor(lowerOp.re);
45314
- upper = Math.floor(upperOp.re);
45708
+ const [firstOp, secondOp] = ops;
45709
+ if (secondOp !== void 0) {
45710
+ let lower = Math.floor(firstOp.re);
45711
+ let upper = Math.floor(secondOp.re);
45315
45712
  if (isNaN(lower)) lower = 0;
45316
45713
  if (isNaN(upper)) upper = 0;
45714
+ return ce.number(lower + Math.floor(Math.random() * (upper - lower)));
45715
+ }
45716
+ if (firstOp.type.matches("integer")) {
45717
+ let n = Math.floor(firstOp.re);
45718
+ if (isNaN(n)) n = 0;
45719
+ return ce.number(Math.floor(Math.random() * n));
45317
45720
  }
45318
- return ce.number(lower + Math.floor(Math.random() * (upper - lower)));
45721
+ const seed = firstOp.re;
45722
+ if (isNaN(seed)) return ce.number(0);
45723
+ return ce.number(deterministicRandom(seed));
45319
45724
  }
45320
45725
  },
45321
45726
  // @todo: need review
@@ -45771,6 +46176,14 @@ ${e.message}
45771
46176
  To: {
45772
46177
  description: "Action arrow / mapping (`a \\to b`) \u2014 opaque typed head.",
45773
46178
  signature: "(any, any) -> nothing"
46179
+ },
46180
+ Colon: {
46181
+ description: "Type annotation (`a : b`) \u2014 opaque typed head.",
46182
+ signature: "(any, any) -> expression"
46183
+ },
46184
+ Prime: {
46185
+ description: "Derivative or prime notation (`f'`, `f^{(n)}`) \u2014 opaque typed head until a derivative library handler runs.",
46186
+ signature: "(any, integer?) -> expression"
45774
46187
  }
45775
46188
  }
45776
46189
  ];
@@ -50811,18 +51224,28 @@ ${e.message}
50811
51224
  },
50812
51225
  {
50813
51226
  Sample: {
50814
- description: "Return a random sample of k elements from the collection, without replacement.",
51227
+ description: "Return a random sample of k elements from the collection, without replacement. With an optional `seed` argument, the sample is deterministic.",
50815
51228
  complexity: 8200,
50816
- signature: "(collection, integer) -> list",
50817
- evaluate: ([xs, nArg], { engine: ce }) => {
51229
+ signature: "(collection, integer, real?) -> list",
51230
+ evaluate: ([xs, nArg, seedArg], { engine: ce }) => {
50818
51231
  if (!xs.isFiniteCollection) return void 0;
50819
51232
  const k = toInteger(nArg);
50820
51233
  if (k === null || k < 0) return void 0;
50821
51234
  const data = Array.from(xs.each());
50822
51235
  if (k > data.length) return void 0;
50823
- for (let i = data.length - 1; i > 0; i--) {
50824
- const j = Math.floor(Math.random() * (i + 1));
50825
- [data[i], data[j]] = [data[j], data[i]];
51236
+ const seed = seedArg?.re;
51237
+ if (seed !== void 0 && !Number.isNaN(seed)) {
51238
+ let s = seed;
51239
+ for (let i = data.length - 1; i > 0; i--) {
51240
+ const j = Math.floor(deterministicRandom(s) * (i + 1));
51241
+ [data[i], data[j]] = [data[j], data[i]];
51242
+ s = nextSeed(s);
51243
+ }
51244
+ } else {
51245
+ for (let i = data.length - 1; i > 0; i--) {
51246
+ const j = Math.floor(Math.random() * (i + 1));
51247
+ [data[i], data[j]] = [data[j], data[i]];
51248
+ }
50826
51249
  }
50827
51250
  const sample = data.slice(0, k);
50828
51251
  return ce.function("List", sample);
@@ -53643,6 +54066,20 @@ Error in definition of "${name}"`,
53643
54066
  if (results.length === 1) return results[0];
53644
54067
  return this.engine._fn("List", results);
53645
54068
  }
54069
+ if (def instanceof _BoxedOperatorDefinition && def._isLambda && this.ops.some((x) => isFiniteIndexedCollection(x)) && paramsAreScalar(def)) {
54070
+ const items = zip(this._ops);
54071
+ if (items) {
54072
+ const results = [];
54073
+ while (true) {
54074
+ const { done, value } = items.next();
54075
+ if (done) break;
54076
+ results.push(
54077
+ this.engine._fn(this.operator, value).evaluate(options)
54078
+ );
54079
+ }
54080
+ return this.engine._fn("List", results);
54081
+ }
54082
+ }
53646
54083
  if (materialization !== false && !def.evaluate && this.isLazyCollection)
53647
54084
  return materialize(this, def, options);
53648
54085
  const tail = holdMap(this, (x) => x.evaluate(options));
@@ -53689,6 +54126,22 @@ Error in definition of "${name}"`,
53689
54126
  (resolved) => this.engine._fn("List", resolved)
53690
54127
  );
53691
54128
  }
54129
+ if (def instanceof _BoxedOperatorDefinition && def._isLambda && this.ops.some((x) => isFiniteIndexedCollection(x)) && paramsAreScalar(def)) {
54130
+ const items = zip(this._ops);
54131
+ if (items) {
54132
+ const results = [];
54133
+ while (true) {
54134
+ const { done, value } = items.next();
54135
+ if (done) break;
54136
+ results.push(
54137
+ this.engine._fn(this.operator, value).evaluateAsync(options)
54138
+ );
54139
+ }
54140
+ return Promise.all(results).then(
54141
+ (resolved) => this.engine._fn("List", resolved)
54142
+ );
54143
+ }
54144
+ }
53692
54145
  const tail = await holdMapAsync(
53693
54146
  this,
53694
54147
  async (x) => await x.evaluateAsync(options)
@@ -53903,8 +54356,47 @@ Error in definition of "${name}"`,
53903
54356
  const ops = expr2.ops.map((x) => x.evaluate(options));
53904
54357
  if (!value || value.type.isUnknown)
53905
54358
  return expr2.engine.function(expr2.operator, ops);
54359
+ if (ops.some((x) => isFiniteIndexedCollection(x)) && paramsAreScalar(value.type.type)) {
54360
+ const items = zip(ops);
54361
+ if (items) {
54362
+ const results = [];
54363
+ while (true) {
54364
+ const { done, value: zipped } = items.next();
54365
+ if (done) break;
54366
+ results.push(apply(value, zipped).evaluate(options));
54367
+ }
54368
+ return expr2.engine._fn("List", results);
54369
+ }
54370
+ }
53906
54371
  return apply(value, ops);
53907
54372
  }
54373
+ function paramsAreScalar(source) {
54374
+ const sigType = isOperatorDefinition(source) ? source.signature?.type : source;
54375
+ if (!sigType || typeof sigType === "string") return true;
54376
+ if (sigType.kind !== "signature") return true;
54377
+ const args = [
54378
+ ...sigType.args ?? [],
54379
+ ...sigType.optArgs ?? [],
54380
+ ...sigType.variadicArg ? [sigType.variadicArg] : []
54381
+ ];
54382
+ return args.every((arg) => isScalarType(arg.type));
54383
+ }
54384
+ function isOperatorDefinition(source) {
54385
+ return typeof source === "object" && source !== null && "signature" in source;
54386
+ }
54387
+ function isScalarType(t) {
54388
+ if (typeof t === "string") {
54389
+ if (t === "collection" || t === "indexed_collection" || t === "list" || t === "tuple" || t === "set" || t === "dictionary" || t === "record" || t === "function")
54390
+ return false;
54391
+ return true;
54392
+ }
54393
+ 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")
54394
+ return false;
54395
+ if (t.kind === "union" || t.kind === "intersection")
54396
+ return t.types.every((x) => isScalarType(x));
54397
+ if (t.kind === "negation") return isScalarType(t.type);
54398
+ return true;
54399
+ }
53908
54400
  function materialize(expr2, def, options) {
53909
54401
  if (!expr2.isValid || options?.materialization === false) return expr2;
53910
54402
  let materialization = options?.materialization ?? false;
@@ -53912,6 +54404,11 @@ Error in definition of "${name}"`,
53912
54404
  materialization = DEFAULT_MATERIALIZATION;
53913
54405
  const isIndexed = expr2.isIndexedCollection;
53914
54406
  const isFinite2 = expr2.isFiniteCollection;
54407
+ if (isIndexed && isFinite2) {
54408
+ const count = expr2.count;
54409
+ if (count !== void 0 && count > expr2.engine.maxCollectionSize)
54410
+ return expr2;
54411
+ }
53915
54412
  const xs = [];
53916
54413
  if (!expr2.isEmptyCollection) {
53917
54414
  if (!isIndexed || !isFinite2) {
@@ -54139,7 +54636,7 @@ Error in definition of "${name}"`,
54139
54636
  const eltType = widen(
54140
54637
  ...Object.values(this._keyValues).map((op) => op.type.type)
54141
54638
  );
54142
- this._type = this.engine.type(`dictionary<${eltType}>`);
54639
+ this._type = new BoxedType({ kind: "dictionary", values: eltType });
54143
54640
  return this._type;
54144
54641
  }
54145
54642
  get isPure() {
@@ -54417,6 +54914,7 @@ Error in definition of "${name}"`,
54417
54914
  }
54418
54915
  if (typeof expr2 === "number" || expr2 instanceof BigDecimal || expr2 instanceof Complex)
54419
54916
  return ce.number(expr2);
54917
+ if (typeof expr2 === "boolean") return ce.symbol(expr2 ? "True" : "False");
54420
54918
  if (typeof expr2 === "string") {
54421
54919
  if (matchesSymbol(expr2)) {
54422
54920
  const sym2 = symbol(expr2);
@@ -55595,6 +56093,13 @@ Error in definition of "${name}"`,
55595
56093
  * GLSL (no dynamic arrays, no push). A compile-time error is thrown.
55596
56094
  * TODO(E3-GLSL): support GLSL multi-Element via a pre-declared fixed-size
55597
56095
  * array or by unrolling when bounds are known at compile time.
56096
+ *
56097
+ * Known issue (imperative form): the IIFE generated by form (1) has no
56098
+ * `return` statement, so `Loop(body, Element(i, Range(lo, hi)))` compiled
56099
+ * to JS evaluates to `undefined` at runtime, while CE evaluation returns a
56100
+ * `List` of body values. See `test/compute-engine/a1-c1-compile-parity.test.ts`
56101
+ * ("Loop compiles in JS") for the verify-only test that locks in the
56102
+ * current behavior.
55598
56103
  */
55599
56104
  static compileForLoop(args, target) {
55600
56105
  if (!args[0]) throw new Error("Loop: no body");
@@ -60231,8 +60736,8 @@ Error in definition of "${name}"`,
60231
60736
  }
60232
60737
  if (effectiveOp === "greater" || effectiveOp === "greaterEqual") {
60233
60738
  const isStrict = effectiveOp === "greater";
60234
- if (bounds.lowerBound !== void 0) {
60235
- const lowerVal = isNumber(bounds.lowerBound) ? bounds.lowerBound.numericValue : void 0;
60739
+ if (bounds.lower !== void 0) {
60740
+ const lowerVal = isNumber(bounds.lower) ? bounds.lower.numericValue : void 0;
60236
60741
  if (typeof lowerVal === "number" && isFinite(lowerVal)) {
60237
60742
  if (isStrict) {
60238
60743
  if (lowerVal > k) return "tautology";
@@ -60244,8 +60749,8 @@ Error in definition of "${name}"`,
60244
60749
  }
60245
60750
  }
60246
60751
  }
60247
- if (bounds.upperBound !== void 0) {
60248
- const upperVal = isNumber(bounds.upperBound) ? bounds.upperBound.numericValue : void 0;
60752
+ if (bounds.upper !== void 0) {
60753
+ const upperVal = isNumber(bounds.upper) ? bounds.upper.numericValue : void 0;
60249
60754
  if (typeof upperVal === "number" && isFinite(upperVal)) {
60250
60755
  if (isStrict) {
60251
60756
  if (upperVal < k) return "contradiction";
@@ -60260,8 +60765,8 @@ Error in definition of "${name}"`,
60260
60765
  }
60261
60766
  } else {
60262
60767
  const isStrict = effectiveOp === "less";
60263
- if (bounds.upperBound !== void 0) {
60264
- const upperVal = isNumber(bounds.upperBound) ? bounds.upperBound.numericValue : void 0;
60768
+ if (bounds.upper !== void 0) {
60769
+ const upperVal = isNumber(bounds.upper) ? bounds.upper.numericValue : void 0;
60265
60770
  if (typeof upperVal === "number" && isFinite(upperVal)) {
60266
60771
  if (isStrict) {
60267
60772
  if (upperVal < k) return "tautology";
@@ -60272,8 +60777,8 @@ Error in definition of "${name}"`,
60272
60777
  }
60273
60778
  }
60274
60779
  }
60275
- if (bounds.lowerBound !== void 0) {
60276
- const lowerVal = isNumber(bounds.lowerBound) ? bounds.lowerBound.numericValue : void 0;
60780
+ if (bounds.lower !== void 0) {
60781
+ const lowerVal = isNumber(bounds.lower) ? bounds.lower.numericValue : void 0;
60277
60782
  if (typeof lowerVal === "number" && isFinite(lowerVal)) {
60278
60783
  if (isStrict) {
60279
60784
  if (lowerVal > k) return "contradiction";
@@ -60501,7 +61006,7 @@ Error in definition of "${name}"`,
60501
61006
  const patOp1B2 = pat.op1;
60502
61007
  if (isSymbol2(patOp1B2)) {
60503
61008
  const bounds = getInequalityBoundsFromAssumptions(ce, patOp1B2.symbol);
60504
- const bound = isLower ? bounds.lowerBound : bounds.upperBound;
61009
+ const bound = isLower ? bounds.lower : bounds.upper;
60505
61010
  const strictOk = isLower ? bounds.lowerStrict : bounds.upperStrict;
60506
61011
  if (bound !== void 0 && (!isStrict || strictOk === true))
60507
61012
  pushResult({ [boundWildcard]: bound });
@@ -60511,7 +61016,7 @@ Error in definition of "${name}"`,
60511
61016
  if (symbolWildcard && !symbolWildcard.startsWith("__")) {
60512
61017
  for (const s of candidatesFromAssumptions()) {
60513
61018
  const bounds = getInequalityBoundsFromAssumptions(ce, s);
60514
- const bound = isLower ? bounds.lowerBound : bounds.upperBound;
61019
+ const bound = isLower ? bounds.lower : bounds.upper;
60515
61020
  const strictOk = isLower ? bounds.lowerStrict : bounds.upperStrict;
60516
61021
  if (bound === void 0 || isStrict && strictOk !== true)
60517
61022
  continue;
@@ -61543,6 +62048,7 @@ Error in definition of "${name}"`,
61543
62048
  return `_SYS.cexp(${compile3(args[0])})`;
61544
62049
  return `Math.exp(${compile3(args[0])})`;
61545
62050
  },
62051
+ First: (args, compile3) => `${compile3(args[0])}[0]`,
61546
62052
  Floor: (args, compile3) => {
61547
62053
  if (BaseCompiler.isIntegerValued(args[0])) return compile3(args[0]);
61548
62054
  return `Math.floor(${compile3(args[0])})`;
@@ -61701,7 +62207,20 @@ Error in definition of "${name}"`,
61701
62207
  if (nConst !== void 0) return `Math.pow(${compile3(arg)}, ${1 / nConst})`;
61702
62208
  return `Math.pow(${compile3(arg)}, 1 / (${compile3(exp3)}))`;
61703
62209
  },
61704
- Random: "Math.random",
62210
+ Random: (args, compile3) => {
62211
+ if (args.length === 0) return "Math.random()";
62212
+ if (args.length === 2) {
62213
+ const m = compile3(args[0]);
62214
+ const n = compile3(args[1]);
62215
+ return `((${m}) + Math.floor(Math.random() * ((${n}) - (${m}))))`;
62216
+ }
62217
+ const arg = args[0];
62218
+ if (BaseCompiler.isIntegerValued(arg)) {
62219
+ return `Math.floor(Math.random() * (${compile3(arg)}))`;
62220
+ }
62221
+ const a = compile3(arg);
62222
+ return `(() => { const _s = (${a}) * 12.9898; const _v = Math.sin(_s) * 43758.5453; return _v - Math.floor(_v); })()`;
62223
+ },
61705
62224
  Round: (args, compile3) => {
61706
62225
  if (BaseCompiler.isIntegerValued(args[0])) return compile3(args[0]);
61707
62226
  return `Math.round(${compile3(args[0])})`;
@@ -61729,6 +62248,7 @@ Error in definition of "${name}"`,
61729
62248
  if (BaseCompiler.isComplexValued(arg)) return `_SYS.csech(${compile3(arg)})`;
61730
62249
  return `1 / Math.cosh(${compile3(arg)})`;
61731
62250
  },
62251
+ Second: (args, compile3) => `${compile3(args[0])}[1]`,
61732
62252
  Heaviside: "_SYS.heaviside",
61733
62253
  Sign: "Math.sign",
61734
62254
  Sinc: "_SYS.sinc",
@@ -61761,6 +62281,7 @@ Error in definition of "${name}"`,
61761
62281
  return `_SYS.ctanh(${compile3(args[0])})`;
61762
62282
  return `Math.tanh(${compile3(args[0])})`;
61763
62283
  },
62284
+ Third: (args, compile3) => `${compile3(args[0])}[2]`,
61764
62285
  Mod: ([a, b], compile3) => {
61765
62286
  if (a === null || b === null) throw new Error("Mod: missing argument");
61766
62287
  const ca = compile3(a);
@@ -63040,6 +63561,14 @@ Error in definition of "${name}"`,
63040
63561
  return `exp(${compile3(args[0])})`;
63041
63562
  },
63042
63563
  Exp2: "exp2",
63564
+ // Component access — assumes the argument compiles to a vec2/vec3/vec4
63565
+ // (the common case for 2D/3D points). For 5+-element tuples that compile
63566
+ // to `float[N]` arrays, swizzle access is invalid GLSL and the shader
63567
+ // will fail to compile; that's an edge case `First`/`Second`/`Third`
63568
+ // aren't designed for. Vec swizzles are identical between GLSL and WGSL.
63569
+ First: (args, compile3) => `${compile3(args[0])}.x`,
63570
+ Second: (args, compile3) => `${compile3(args[0])}.y`,
63571
+ Third: (args, compile3) => `${compile3(args[0])}.z`,
63043
63572
  Floor: (args, compile3) => {
63044
63573
  if (BaseCompiler.isIntegerValued(args[0])) return compile3(args[0]);
63045
63574
  return `floor(${compile3(args[0])})`;
@@ -63517,6 +64046,39 @@ Error in definition of "${name}"`,
63517
64046
  // Sum/Product — unrolled or for-loop
63518
64047
  Sum: (args, compile3, target) => compileGPUSumProduct("Sum", args, compile3, target),
63519
64048
  Product: (args, compile3, target) => compileGPUSumProduct("Product", args, compile3, target),
64049
+ // Range — inline constant array literal (bounds must be compile-time constants)
64050
+ Range: (args, _compile2, target) => {
64051
+ if (args.length < 2 || args.length > 3) {
64052
+ throw new Error(
64053
+ "Range: GPU compile expects 2 or 3 arguments (lo, hi, step?)"
64054
+ );
64055
+ }
64056
+ const lo = args[0].re;
64057
+ const hi = args[1].re;
64058
+ const step = args.length === 3 ? args[2].re : 1;
64059
+ if (!Number.isFinite(lo) || !Number.isFinite(hi) || !Number.isFinite(step)) {
64060
+ throw new Error(
64061
+ "Range: GPU compile requires constant numeric bounds (non-constant ranges must be materialized at JS host then uploaded as a uniform)"
64062
+ );
64063
+ }
64064
+ if (step === 0) throw new Error("Range: step cannot be zero");
64065
+ const count = Math.max(0, Math.floor((hi - lo) / step) + 1);
64066
+ if (count === 0) {
64067
+ throw new Error(
64068
+ "Range: empty range (lo > hi for positive step, or lo < hi for negative step)"
64069
+ );
64070
+ }
64071
+ if (count > 256) {
64072
+ throw new Error(
64073
+ `Range: GPU compile inlines ranges up to 256 elements (got ${count})`
64074
+ );
64075
+ }
64076
+ const values = [];
64077
+ for (let i = 0; i < count; i++) values.push(lo + i * step);
64078
+ const isWGSL = target.language === "wgsl";
64079
+ const arrayType = isWGSL ? `array<f32, ${count}>` : `float[${count}]`;
64080
+ return `${arrayType}(${values.map(formatGPUNumber).join(", ")})`;
64081
+ },
63520
64082
  // Loop — GPU for-loop (no IIFE, no let)
63521
64083
  Loop: (args, _compile2, target) => {
63522
64084
  if (!args[0]) throw new Error("Loop: no body");
@@ -63545,6 +64107,134 @@ Error in definition of "${name}"`,
63545
64107
  ${bodyCode};
63546
64108
  }`;
63547
64109
  },
64110
+ // Statistical functions
64111
+ /**
64112
+ * GCD of two scalar arguments.
64113
+ *
64114
+ * Uses a preamble helper `_gpu_gcd` (Euclidean algorithm via `mod`).
64115
+ * Only two-argument form is supported in GPU targets.
64116
+ */
64117
+ GCD: (args, compile3) => {
64118
+ if (args.length < 2) throw new Error("GCD: need at least two arguments");
64119
+ if (args.length > 2)
64120
+ throw new Error("GCD: GPU target supports only two-argument GCD");
64121
+ const a = args[0];
64122
+ const b = args[1];
64123
+ if (a === null || b === null) throw new Error("GCD: missing argument");
64124
+ return `_gpu_gcd(${compile3(a)}, ${compile3(b)})`;
64125
+ },
64126
+ /**
64127
+ * Variance of a compile-time-known list.
64128
+ *
64129
+ * Accepts either a single `List(...)` argument or N scalar arguments.
64130
+ * Generates fully inline code: computes mean then sum of squared deviations,
64131
+ * divided by (N-1) for sample variance (matches JS `_SYS.variance`).
64132
+ */
64133
+ Variance: (args, compile3) => {
64134
+ let elems;
64135
+ if (args.length === 1 && isFunction2(args[0], "List")) {
64136
+ elems = args[0].ops;
64137
+ } else if (args.length >= 2) {
64138
+ elems = args;
64139
+ } else {
64140
+ throw new Error(
64141
+ "Variance: GPU target requires a List argument or at least 2 scalar arguments"
64142
+ );
64143
+ }
64144
+ const n = elems.length;
64145
+ if (n < 2) throw new Error("Variance: need at least 2 elements");
64146
+ const compiled = elems.map((e) => compile3(e));
64147
+ const sum = compiled.join(" + ");
64148
+ const mean2 = `((${sum}) / ${formatGPUNumber(n)})`;
64149
+ const sqDiffs = compiled.map((c) => `(${c} - ${mean2}) * (${c} - ${mean2})`).join(" + ");
64150
+ return `((${sqDiffs}) / ${formatGPUNumber(n - 1)})`;
64151
+ },
64152
+ /**
64153
+ * Median of a compile-time-known list.
64154
+ *
64155
+ * Accepts either a single `List(...)` argument or N scalar arguments.
64156
+ * For N ≤ 8: generates a fully unrolled inline sorting network followed by
64157
+ * a middle-element pick. For larger N, throws (too large to inline cleanly).
64158
+ *
64159
+ * The sorting network uses the "odd-even merge sort" comparator pattern
64160
+ * inlined as `min`/`max` calls — no GPU statements required.
64161
+ */
64162
+ Median: (args, compile3) => {
64163
+ let elems;
64164
+ if (args.length === 1 && isFunction2(args[0], "List")) {
64165
+ elems = args[0].ops;
64166
+ } else if (args.length >= 1) {
64167
+ elems = args;
64168
+ } else {
64169
+ throw new Error(
64170
+ "Median: GPU target requires a List argument or at least 1 scalar argument"
64171
+ );
64172
+ }
64173
+ const n = elems.length;
64174
+ if (n === 0) throw new Error("Median: empty list");
64175
+ if (n > 8) {
64176
+ throw new Error(
64177
+ `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.`
64178
+ );
64179
+ }
64180
+ const compiled = elems.map((e) => compile3(e));
64181
+ if (n === 1) return compiled[0];
64182
+ return `_gpu_median_${n}(${compiled.join(", ")})`;
64183
+ },
64184
+ /**
64185
+ * Deterministic pseudorandom for GPU.
64186
+ *
64187
+ * All emitted forms return a GLSL `float` (or WGSL `f32`) so the result
64188
+ * composes with surrounding float arithmetic without explicit casts. The
64189
+ * "integer-bound" forms return an integer-valued float (the result of
64190
+ * `floor`), matching the convention used by `Floor` and other ostensibly
64191
+ * integer-returning operators in this target.
64192
+ *
64193
+ * - 0 args (GLSL only): fall back to a fragment-coord-derived seed.
64194
+ * Only meaningful in fragment shaders (gl_FragCoord is FS-only).
64195
+ * - 0 args (WGSL): throws — WGSL has no built-in fragment coordinate;
64196
+ * caller must provide an explicit seed.
64197
+ * - 1 arg, real-typed: `_gpu_random(seed)` — deterministic float in [0, 1)
64198
+ * - 1 arg, integer-typed: `floor(_gpu_random(float(n)) * float(n))` —
64199
+ * integer-valued float in {0, 1, ..., n-1}. The seed is derived from
64200
+ * `n` itself, so the result is per-pixel-and-n deterministic in GLSL.
64201
+ * - 2 args (integer m, n): float in [m, n), seeded from gl_FragCoord.
64202
+ *
64203
+ * JS-side `Random` has matching semantics (see `library/core.ts`'s
64204
+ * polymorphic dispatch). JS↔GLSL parity is approximate — same seed yields
64205
+ * a similar value, not bit-identical, due to fp64 vs fp32 and platform
64206
+ * `sin` differences.
64207
+ */
64208
+ Random: (args, compile3, target) => {
64209
+ if (args.length === 0) {
64210
+ if (target.language === "wgsl") {
64211
+ throw new Error(
64212
+ "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."
64213
+ );
64214
+ }
64215
+ return "_gpu_random(gl_FragCoord.x + gl_FragCoord.y * 1024.0)";
64216
+ }
64217
+ if (args.length === 1) {
64218
+ const arg = args[0];
64219
+ if (BaseCompiler.isIntegerValued(arg)) {
64220
+ const compiled = compile3(arg);
64221
+ return `floor(_gpu_random(float(${compiled})) * float(${compiled}))`;
64222
+ }
64223
+ return `_gpu_random(${compile3(arg)})`;
64224
+ }
64225
+ if (args.length === 2) {
64226
+ if (target.language === "wgsl") {
64227
+ throw new Error(
64228
+ "Random(m, n): WGSL compile requires explicit seeding. Use a seeded variant or compute the integer range manually."
64229
+ );
64230
+ }
64231
+ const m = compile3(args[0]);
64232
+ const n = compile3(args[1]);
64233
+ const seed = "_gpu_random(gl_FragCoord.x + gl_FragCoord.y * 1024.0)";
64234
+ return `(float(${m}) + floor(${seed} * float((${n}) - (${m}))))`;
64235
+ }
64236
+ throw new Error("Random: GPU compile expects 0, 1, or 2 arguments");
64237
+ },
63548
64238
  // Function (lambda) — not supported in GPU
63549
64239
  Function: () => {
63550
64240
  throw new Error(
@@ -64143,6 +64833,212 @@ fn _fractal_julia(z_in: vec2f, c: vec2f, maxIter: i32) -> f32 {
64143
64833
  }
64144
64834
  return 1.0;
64145
64835
  }
64836
+ `;
64837
+ var GPU_GCD_PREAMBLE_GLSL = `
64838
+ float _gpu_gcd(float a, float b) {
64839
+ a = abs(a); b = abs(b);
64840
+ for (int i = 0; i < 32; i++) {
64841
+ if (b < 0.5) break;
64842
+ float t = mod(a, b);
64843
+ a = b;
64844
+ b = t;
64845
+ }
64846
+ return a;
64847
+ }
64848
+ `;
64849
+ var GPU_GCD_PREAMBLE_WGSL = `
64850
+ fn _gpu_gcd(a_in: f32, b_in: f32) -> f32 {
64851
+ var a = abs(a_in); var b = abs(b_in);
64852
+ for (var i: i32 = 0; i < 32; i++) {
64853
+ if (b < 0.5) { break; }
64854
+ let t = a % b;
64855
+ a = b;
64856
+ b = t;
64857
+ }
64858
+ return a;
64859
+ }
64860
+ `;
64861
+ var GPU_RANDOM_PREAMBLE_GLSL = `
64862
+ // Deterministic pseudorandom in [0, 1) from a float seed.
64863
+ // Standard fract-sin hash; reproducible across runs for the same seed.
64864
+ // Note: this hash exhibits visible banding near seed \u2248 k\u03C0 for integer k.
64865
+ // For high-quality shader random, callers should use a more robust hash
64866
+ // (e.g. PCG or xxHash) and pre-seed it appropriately.
64867
+ float _gpu_random(float seed) {
64868
+ return fract(sin(seed * 12.9898) * 43758.5453);
64869
+ }
64870
+ `;
64871
+ var GPU_RANDOM_PREAMBLE_WGSL = `
64872
+ // Deterministic pseudorandom in [0, 1) from a float seed.
64873
+ // Standard fract-sin hash; reproducible across runs for the same seed.
64874
+ // Note: this hash exhibits visible banding near seed \u2248 k\u03C0 for integer k.
64875
+ // For high-quality shader random, callers should use a more robust hash
64876
+ // (e.g. PCG or xxHash) and pre-seed it appropriately.
64877
+ fn _gpu_random(seed: f32) -> f32 {
64878
+ return fract(sin(seed * 12.9898) * 43758.5453);
64879
+ }
64880
+ `;
64881
+ var GPU_MEDIAN_PREAMBLE_GLSL = `
64882
+ float _gpu_median_2(float a, float b) {
64883
+ return (a + b) * 0.5;
64884
+ }
64885
+ float _gpu_median_3(float a, float b, float c) {
64886
+ return max(min(a, b), min(max(a, b), c));
64887
+ }
64888
+ float _gpu_median_4(float a, float b, float c, float d) {
64889
+ float lo = max(min(a, b), min(c, d));
64890
+ float hi = min(max(a, b), max(c, d));
64891
+ return (lo + hi) * 0.5;
64892
+ }
64893
+ float _gpu_median_5(float a, float b, float c, float d, float e) {
64894
+ // 9-comparator Bose-Nelson sort; v2 holds the median.
64895
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e;
64896
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
64897
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
64898
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
64899
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
64900
+ t=min(v0,v3); v3=max(v0,v3); v0=t;
64901
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
64902
+ t=min(v1,v4); v4=max(v1,v4); v1=t;
64903
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
64904
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
64905
+ return v2;
64906
+ }
64907
+ float _gpu_median_6(float a, float b, float c, float d, float e, float f) {
64908
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f;
64909
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
64910
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
64911
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
64912
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
64913
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
64914
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
64915
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
64916
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
64917
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
64918
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
64919
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
64920
+ return (v2 + v3) * 0.5;
64921
+ }
64922
+ float _gpu_median_7(float a, float b, float c, float d, float e, float f, float g) {
64923
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f,v6=g;
64924
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
64925
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
64926
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
64927
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
64928
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
64929
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
64930
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
64931
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
64932
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
64933
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
64934
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
64935
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
64936
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
64937
+ return v3;
64938
+ }
64939
+ float _gpu_median_8(float a, float b, float c, float d, float e, float f, float g, float h) {
64940
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f,v6=g,v7=h;
64941
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
64942
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
64943
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
64944
+ t=min(v6,v7); v7=max(v6,v7); v6=t;
64945
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
64946
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
64947
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
64948
+ t=min(v5,v7); v7=max(v5,v7); v5=t;
64949
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
64950
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
64951
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
64952
+ t=min(v3,v7); v7=max(v3,v7); v3=t;
64953
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
64954
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
64955
+ t=min(v5,v6); v6=max(v5,v6); v5=t;
64956
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
64957
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
64958
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
64959
+ return (v3 + v4) * 0.5;
64960
+ }
64961
+ `;
64962
+ var GPU_MEDIAN_PREAMBLE_WGSL = `
64963
+ fn _gpu_median_2(a: f32, b: f32) -> f32 {
64964
+ return (a + b) * 0.5;
64965
+ }
64966
+ fn _gpu_median_3(a: f32, b: f32, c: f32) -> f32 {
64967
+ return max(min(a, b), min(max(a, b), c));
64968
+ }
64969
+ fn _gpu_median_4(a: f32, b: f32, c: f32, d: f32) -> f32 {
64970
+ let lo = max(min(a, b), min(c, d));
64971
+ let hi = min(max(a, b), max(c, d));
64972
+ return (lo + hi) * 0.5;
64973
+ }
64974
+ fn _gpu_median_5(a: f32, b: f32, c: f32, d: f32, e: f32) -> f32 {
64975
+ // 9-comparator Bose-Nelson sort; v2 holds the median.
64976
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var t: f32;
64977
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
64978
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
64979
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
64980
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
64981
+ t=min(v0,v3); v3=max(v0,v3); v0=t;
64982
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
64983
+ t=min(v1,v4); v4=max(v1,v4); v1=t;
64984
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
64985
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
64986
+ return v2;
64987
+ }
64988
+ fn _gpu_median_6(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) -> f32 {
64989
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var v5=f; var t: f32;
64990
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
64991
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
64992
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
64993
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
64994
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
64995
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
64996
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
64997
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
64998
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
64999
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
65000
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
65001
+ return (v2 + v3) * 0.5;
65002
+ }
65003
+ fn _gpu_median_7(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32, g: f32) -> f32 {
65004
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var v5=f; var v6=g; var t: f32;
65005
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
65006
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
65007
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
65008
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
65009
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
65010
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
65011
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
65012
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
65013
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
65014
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
65015
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
65016
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
65017
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
65018
+ return v3;
65019
+ }
65020
+ fn _gpu_median_8(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32, g: f32, h: f32) -> f32 {
65021
+ 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;
65022
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
65023
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
65024
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
65025
+ t=min(v6,v7); v7=max(v6,v7); v6=t;
65026
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
65027
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
65028
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
65029
+ t=min(v5,v7); v7=max(v5,v7); v5=t;
65030
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
65031
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
65032
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
65033
+ t=min(v3,v7); v7=max(v3,v7); v3=t;
65034
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
65035
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
65036
+ t=min(v5,v6); v6=max(v5,v6); v5=t;
65037
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
65038
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
65039
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
65040
+ return (v3 + v4) * 0.5;
65041
+ }
64146
65042
  `;
64147
65043
  var GPU_COLOR_PREAMBLE_GLSL = `
64148
65044
  float _gpu_srgb_to_linear(float c) {
@@ -64821,6 +65717,12 @@ fn _gpu_apca(lch_bg: vec3f, lch_fg: vec3f) -> f32 {
64821
65717
  if (code.includes("_fractal_")) {
64822
65718
  preamble += this.languageId === "wgsl" ? GPU_FRACTAL_PREAMBLE_WGSL : GPU_FRACTAL_PREAMBLE_GLSL;
64823
65719
  }
65720
+ if (code.includes("_gpu_random"))
65721
+ preamble += this.languageId === "wgsl" ? GPU_RANDOM_PREAMBLE_WGSL : GPU_RANDOM_PREAMBLE_GLSL;
65722
+ if (code.includes("_gpu_gcd"))
65723
+ preamble += this.languageId === "wgsl" ? GPU_GCD_PREAMBLE_WGSL : GPU_GCD_PREAMBLE_GLSL;
65724
+ if (code.includes("_gpu_median_"))
65725
+ preamble += this.languageId === "wgsl" ? GPU_MEDIAN_PREAMBLE_WGSL : GPU_MEDIAN_PREAMBLE_GLSL;
64824
65726
  if (code.includes("_gpu_srgb_to") || code.includes("_gpu_oklab") || code.includes("_gpu_oklch") || code.includes("_gpu_color_mix") || code.includes("_gpu_apca")) {
64825
65727
  preamble += this.languageId === "wgsl" ? GPU_COLOR_PREAMBLE_WGSL : GPU_COLOR_PREAMBLE_GLSL;
64826
65728
  }
@@ -67046,6 +67948,7 @@ ${workgroupAttr}fn main(${paramStr})${returnStr} {
67046
67948
  _timeLimit = 2e3;
67047
67949
  _iterationLimit = 1024;
67048
67950
  _recursionLimit = 1024;
67951
+ _maxCollectionSize = 1e4;
67049
67952
  _deadline = void 0;
67050
67953
  _isVerifying = false;
67051
67954
  get timeLimit() {
@@ -67066,6 +67969,12 @@ ${workgroupAttr}fn main(${paramStr})${returnStr} {
67066
67969
  set recursionLimit(value) {
67067
67970
  this._recursionLimit = value <= 0 ? Number.POSITIVE_INFINITY : value;
67068
67971
  }
67972
+ get maxCollectionSize() {
67973
+ return this._maxCollectionSize;
67974
+ }
67975
+ set maxCollectionSize(value) {
67976
+ this._maxCollectionSize = value <= 0 ? Number.POSITIVE_INFINITY : value;
67977
+ }
67069
67978
  get deadline() {
67070
67979
  return this._deadline;
67071
67980
  }
@@ -69526,6 +70435,23 @@ ${code}`;
69526
70435
  set recursionLimit(t) {
69527
70436
  this._runtimeState.recursionLimit = t;
69528
70437
  }
70438
+ /** Maximum number of elements a collection may have when materialized
70439
+ * (converted from a lazy form to a `List`). Default: 10,000.
70440
+ *
70441
+ * When a materialization would exceed this size, the operation leaves
70442
+ * the expression in its lazy form. Consumers can detect oversize
70443
+ * collections via the symbolic form's `count`.
70444
+ *
70445
+ * Set to `Infinity` (or `0` / a negative number) to disable the cap.
70446
+ *
70447
+ * @experimental
70448
+ */
70449
+ get maxCollectionSize() {
70450
+ return this._runtimeState.maxCollectionSize;
70451
+ }
70452
+ set maxCollectionSize(t) {
70453
+ this._runtimeState.maxCollectionSize = t;
70454
+ }
69529
70455
  /**
69530
70456
  * Flag to prevent infinite recursion in the verify/ask/equality checking cycle.
69531
70457
  *
@@ -69802,6 +70728,18 @@ ${code}`;
69802
70728
  lookupDefinition(id) {
69803
70729
  return lookupDefinition(this, id);
69804
70730
  }
70731
+ normalizeIdentifier(latex) {
70732
+ if (!latex) return "";
70733
+ if (isValidSymbol(latex)) return latex;
70734
+ this.pushScope();
70735
+ try {
70736
+ const expr2 = this.parse(latex);
70737
+ if (isSymbol2(expr2)) return expr2.symbol;
70738
+ } finally {
70739
+ this.popScope();
70740
+ }
70741
+ return "";
70742
+ }
69805
70743
  operatorInfo(head) {
69806
70744
  const def = this.lookupDefinition(head);
69807
70745
  if (!def || !isOperatorDef(def)) return void 0;
@@ -69811,6 +70749,15 @@ ${code}`;
69811
70749
  signature: op.signature
69812
70750
  };
69813
70751
  }
70752
+ symbolInfo(name) {
70753
+ const def = this.lookupDefinition(name);
70754
+ if (!def || !isValueDef(def)) return void 0;
70755
+ const v = def.value;
70756
+ return {
70757
+ kind: v.isConstant ? "constant" : "variable",
70758
+ type: v.type
70759
+ };
70760
+ }
69814
70761
  /**
69815
70762
  * Associate a new definition to a symbol in the current context.
69816
70763
  *
@@ -70263,14 +71210,14 @@ ${code}`;
70263
71210
  _setDefaultEngineFactory(() => new ComputeEngine());
70264
71211
 
70265
71212
  // src/compute-engine.ts
70266
- var version = "0.57.0";
71213
+ var version = "0.58.0";
70267
71214
  ComputeEngine._latexSyntaxFactory = () => new LatexSyntax();
70268
71215
  _setDefaultEngineFactory(
70269
71216
  () => new ComputeEngine({ latexSyntax: new LatexSyntax() })
70270
71217
  );
70271
71218
  globalThis[/* @__PURE__ */ Symbol.for("io.cortexjs.compute-engine")] = {
70272
71219
  ComputeEngine: ComputeEngine.prototype.constructor,
70273
- version: "0.57.0"
71220
+ version: "0.58.0"
70274
71221
  };
70275
71222
  return __toCommonJS(compute_engine_exports);
70276
71223
  })();