@cortex-js/compute-engine 0.57.0 → 0.59.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 (270) hide show
  1. package/README.md +4 -0
  2. package/dist/compile.esm.js +2376 -501
  3. package/dist/compile.min.esm.js +316 -68
  4. package/dist/compile.min.umd.cjs +316 -68
  5. package/dist/compile.umd.cjs +2376 -501
  6. package/dist/compute-engine.esm.js +15717 -12444
  7. package/dist/compute-engine.min.esm.js +331 -83
  8. package/dist/compute-engine.min.umd.cjs +330 -82
  9. package/dist/compute-engine.umd.cjs +15717 -12444
  10. package/dist/core.esm.js +15716 -12443
  11. package/dist/core.min.esm.js +329 -81
  12. package/dist/core.min.umd.cjs +329 -81
  13. package/dist/core.umd.cjs +15716 -12443
  14. package/dist/identities.esm.js +1921 -0
  15. package/dist/identities.min.esm.js +2 -0
  16. package/dist/identities.min.umd.cjs +4 -0
  17. package/dist/identities.umd.cjs +1946 -0
  18. package/dist/interval.esm.js +779 -339
  19. package/dist/interval.min.esm.js +8 -8
  20. package/dist/interval.min.umd.cjs +8 -8
  21. package/dist/interval.umd.cjs +779 -339
  22. package/dist/latex-syntax.esm.js +971 -608
  23. package/dist/latex-syntax.min.esm.js +7 -7
  24. package/dist/latex-syntax.min.umd.cjs +7 -7
  25. package/dist/latex-syntax.umd.cjs +971 -608
  26. package/dist/math-json.esm.js +8 -12
  27. package/dist/math-json.min.esm.js +2 -2
  28. package/dist/math-json.min.umd.cjs +2 -2
  29. package/dist/math-json.umd.cjs +8 -12
  30. package/dist/numerics.esm.js +1382 -226
  31. package/dist/numerics.min.esm.js +16 -5
  32. package/dist/numerics.min.umd.cjs +16 -5
  33. package/dist/numerics.umd.cjs +1382 -226
  34. package/dist/types/big-decimal/big-decimal.d.ts +1 -1
  35. package/dist/types/big-decimal/index.d.ts +1 -1
  36. package/dist/types/big-decimal/transcendentals.d.ts +1 -1
  37. package/dist/types/big-decimal/utils.d.ts +1 -1
  38. package/dist/types/common/ansi-codes.d.ts +1 -1
  39. package/dist/types/common/configuration-change.d.ts +1 -1
  40. package/dist/types/common/fuzzy-string-match.d.ts +1 -1
  41. package/dist/types/common/grapheme-splitter.d.ts +1 -1
  42. package/dist/types/common/interruptible.d.ts +1 -1
  43. package/dist/types/common/one-of.d.ts +1 -1
  44. package/dist/types/common/signals.d.ts +1 -1
  45. package/dist/types/common/type/ast-nodes.d.ts +1 -1
  46. package/dist/types/common/type/boxed-type.d.ts +1 -1
  47. package/dist/types/common/type/lexer.d.ts +1 -1
  48. package/dist/types/common/type/parse.d.ts +1 -208
  49. package/dist/types/common/type/parser.d.ts +124 -2
  50. package/dist/types/common/type/primitive.d.ts +5 -1
  51. package/dist/types/common/type/reduce.d.ts +1 -1
  52. package/dist/types/common/type/serialize.d.ts +1 -1
  53. package/dist/types/common/type/subtype.d.ts +18 -1
  54. package/dist/types/common/type/type-builder.d.ts +1 -1
  55. package/dist/types/common/type/types.d.ts +1 -1
  56. package/dist/types/common/type/utils.d.ts +1 -1
  57. package/dist/types/common/utils.d.ts +1 -1
  58. package/dist/types/compile.d.ts +1 -1
  59. package/dist/types/compute-engine/assume.d.ts +13 -6
  60. package/dist/types/compute-engine/boxed-expression/abstract-boxed-expression.d.ts +3 -1
  61. package/dist/types/compute-engine/boxed-expression/apply.d.ts +1 -1
  62. package/dist/types/compute-engine/boxed-expression/arithmetic-add.d.ts +1 -1
  63. package/dist/types/compute-engine/boxed-expression/arithmetic-mul-div.d.ts +1 -1
  64. package/dist/types/compute-engine/boxed-expression/arithmetic-power.d.ts +1 -1
  65. package/dist/types/compute-engine/boxed-expression/ascii-math.d.ts +1 -1
  66. package/dist/types/compute-engine/boxed-expression/box.d.ts +1 -1
  67. package/dist/types/compute-engine/boxed-expression/boxed-dictionary.d.ts +1 -1
  68. package/dist/types/compute-engine/boxed-expression/boxed-function.d.ts +1 -1
  69. package/dist/types/compute-engine/boxed-expression/boxed-number.d.ts +1 -1
  70. package/dist/types/compute-engine/boxed-expression/boxed-operator-definition.d.ts +7 -1
  71. package/dist/types/compute-engine/boxed-expression/boxed-patterns.d.ts +1 -1
  72. package/dist/types/compute-engine/boxed-expression/boxed-string.d.ts +1 -1
  73. package/dist/types/compute-engine/boxed-expression/boxed-symbol.d.ts +3 -3
  74. package/dist/types/compute-engine/boxed-expression/boxed-tensor.d.ts +1 -1
  75. package/dist/types/compute-engine/boxed-expression/boxed-value-definition.d.ts +1 -1
  76. package/dist/types/compute-engine/boxed-expression/cache.d.ts +1 -1
  77. package/dist/types/compute-engine/boxed-expression/canonical-utils.d.ts +1 -1
  78. package/dist/types/compute-engine/boxed-expression/canonical.d.ts +1 -1
  79. package/dist/types/compute-engine/boxed-expression/compare.d.ts +1 -1
  80. package/dist/types/compute-engine/boxed-expression/constants.d.ts +1 -1
  81. package/dist/types/compute-engine/boxed-expression/constraint-subject.d.ts +140 -0
  82. package/dist/types/compute-engine/boxed-expression/expand.d.ts +1 -1
  83. package/dist/types/compute-engine/boxed-expression/expression-map.d.ts +1 -1
  84. package/dist/types/compute-engine/boxed-expression/factor.d.ts +1 -1
  85. package/dist/types/compute-engine/boxed-expression/flatten.d.ts +1 -1
  86. package/dist/types/compute-engine/boxed-expression/hold.d.ts +1 -1
  87. package/dist/types/compute-engine/boxed-expression/inequality-bounds.d.ts +34 -12
  88. package/dist/types/compute-engine/boxed-expression/init-lazy-refs.d.ts +1 -1
  89. package/dist/types/compute-engine/boxed-expression/invisible-operator.d.ts +1 -1
  90. package/dist/types/compute-engine/boxed-expression/match.d.ts +1 -1
  91. package/dist/types/compute-engine/boxed-expression/negate.d.ts +1 -1
  92. package/dist/types/compute-engine/boxed-expression/numerics.d.ts +1 -1
  93. package/dist/types/compute-engine/boxed-expression/order.d.ts +1 -1
  94. package/dist/types/compute-engine/boxed-expression/pattern-utils.d.ts +1 -1
  95. package/dist/types/compute-engine/boxed-expression/polynomial-degree.d.ts +1 -1
  96. package/dist/types/compute-engine/boxed-expression/polynomials.d.ts +1 -1
  97. package/dist/types/compute-engine/boxed-expression/predicates.d.ts +1 -1
  98. package/dist/types/compute-engine/boxed-expression/rule-index.d.ts +112 -0
  99. package/dist/types/compute-engine/boxed-expression/rules.d.ts +2 -1
  100. package/dist/types/compute-engine/boxed-expression/serialize.d.ts +1 -1
  101. package/dist/types/compute-engine/boxed-expression/sgn.d.ts +1 -1
  102. package/dist/types/compute-engine/boxed-expression/simplify.d.ts +1 -1
  103. package/dist/types/compute-engine/boxed-expression/solve-linear-system.d.ts +1 -1
  104. package/dist/types/compute-engine/boxed-expression/solve.d.ts +1 -1
  105. package/dist/types/compute-engine/boxed-expression/stochastic-equal.d.ts +1 -1
  106. package/dist/types/compute-engine/boxed-expression/trigonometry.d.ts +1 -1
  107. package/dist/types/compute-engine/boxed-expression/type-guards.d.ts +1 -1
  108. package/dist/types/compute-engine/boxed-expression/utils.d.ts +1 -1
  109. package/dist/types/compute-engine/boxed-expression/validate.d.ts +1 -1
  110. package/dist/types/compute-engine/collection-utils.d.ts +1 -1
  111. package/dist/types/compute-engine/compilation/base-compiler.d.ts +8 -1
  112. package/dist/types/compute-engine/compilation/compile-expression.d.ts +1 -1
  113. package/dist/types/compute-engine/compilation/constant-folding.d.ts +16 -1
  114. package/dist/types/compute-engine/compilation/glsl-target.d.ts +1 -1
  115. package/dist/types/compute-engine/compilation/gpu-target.d.ts +58 -5
  116. package/dist/types/compute-engine/compilation/interval-javascript-target.d.ts +4 -4
  117. package/dist/types/compute-engine/compilation/javascript-target.d.ts +1 -1
  118. package/dist/types/compute-engine/compilation/python-target.d.ts +1 -1
  119. package/dist/types/compute-engine/compilation/types.d.ts +1 -1
  120. package/dist/types/compute-engine/compilation/wgsl-target.d.ts +1 -1
  121. package/dist/types/compute-engine/cost-function.d.ts +1 -1
  122. package/dist/types/compute-engine/engine-assumptions.d.ts +1 -1
  123. package/dist/types/compute-engine/engine-cache.d.ts +1 -1
  124. package/dist/types/compute-engine/engine-common-symbols.d.ts +1 -1
  125. package/dist/types/compute-engine/engine-compilation-targets.d.ts +1 -1
  126. package/dist/types/compute-engine/engine-configuration-lifecycle.d.ts +1 -1
  127. package/dist/types/compute-engine/engine-declarations.d.ts +1 -1
  128. package/dist/types/compute-engine/engine-expression-entrypoints.d.ts +1 -1
  129. package/dist/types/compute-engine/engine-extension-contracts.d.ts +1 -1
  130. package/dist/types/compute-engine/engine-library-bootstrap.d.ts +1 -1
  131. package/dist/types/compute-engine/engine-numeric-configuration.d.ts +1 -1
  132. package/dist/types/compute-engine/engine-runtime-state.d.ts +4 -1
  133. package/dist/types/compute-engine/engine-scope.d.ts +1 -1
  134. package/dist/types/compute-engine/engine-sequences.d.ts +1 -1
  135. package/dist/types/compute-engine/engine-simplification-rules.d.ts +10 -2
  136. package/dist/types/compute-engine/engine-startup-coordinator.d.ts +1 -1
  137. package/dist/types/compute-engine/engine-type-resolver.d.ts +1 -1
  138. package/dist/types/compute-engine/engine-validation-entrypoints.d.ts +1 -1
  139. package/dist/types/compute-engine/free-functions.d.ts +1 -1
  140. package/dist/types/compute-engine/function-utils.d.ts +1 -1
  141. package/dist/types/compute-engine/fungrim/loader.d.ts +13 -0
  142. package/dist/types/compute-engine/fungrim/types.d.ts +160 -0
  143. package/dist/types/compute-engine/global-types.d.ts +1 -1
  144. package/dist/types/compute-engine/index.d.ts +63 -2
  145. package/dist/types/compute-engine/interval/arithmetic.d.ts +1 -1
  146. package/dist/types/compute-engine/interval/comparison.d.ts +1 -1
  147. package/dist/types/compute-engine/interval/elementary.d.ts +10 -2
  148. package/dist/types/compute-engine/interval/index.d.ts +2 -2
  149. package/dist/types/compute-engine/interval/trigonometric.d.ts +1 -1
  150. package/dist/types/compute-engine/interval/types.d.ts +1 -1
  151. package/dist/types/compute-engine/interval/util.d.ts +1 -1
  152. package/dist/types/compute-engine/latex-syntax/dictionary/default-dictionary.d.ts +1 -1
  153. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-algebra.d.ts +1 -1
  154. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-arithmetic.d.ts +1 -1
  155. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-calculus.d.ts +1 -1
  156. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-colors.d.ts +1 -1
  157. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-complex.d.ts +1 -1
  158. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-core.d.ts +1 -1
  159. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-linear-algebra.d.ts +1 -1
  160. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-logic.d.ts +1 -1
  161. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-other.d.ts +1 -1
  162. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-relational-operators.d.ts +1 -1
  163. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-sets.d.ts +1 -1
  164. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-statistics.d.ts +1 -1
  165. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-symbols.d.ts +1 -1
  166. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-trigonometry.d.ts +1 -1
  167. package/dist/types/compute-engine/latex-syntax/dictionary/definitions-units.d.ts +1 -1
  168. package/dist/types/compute-engine/latex-syntax/dictionary/definitions.d.ts +1 -1
  169. package/dist/types/compute-engine/latex-syntax/dictionary/indexed-types.d.ts +4 -1
  170. package/dist/types/compute-engine/latex-syntax/latex-syntax.d.ts +1 -1
  171. package/dist/types/compute-engine/latex-syntax/parse-number.d.ts +1 -1
  172. package/dist/types/compute-engine/latex-syntax/parse-symbol.d.ts +1 -1
  173. package/dist/types/compute-engine/latex-syntax/parse.d.ts +3 -2
  174. package/dist/types/compute-engine/latex-syntax/serialize-dms.d.ts +1 -1
  175. package/dist/types/compute-engine/latex-syntax/serialize-number.d.ts +1 -11
  176. package/dist/types/compute-engine/latex-syntax/serializer-style.d.ts +1 -1
  177. package/dist/types/compute-engine/latex-syntax/serializer.d.ts +1 -1
  178. package/dist/types/compute-engine/latex-syntax/tokenizer.d.ts +1 -1
  179. package/dist/types/compute-engine/latex-syntax/types.d.ts +1 -1
  180. package/dist/types/compute-engine/latex-syntax/utils.d.ts +1 -1
  181. package/dist/types/compute-engine/library/arithmetic.d.ts +1 -1
  182. package/dist/types/compute-engine/library/calculus.d.ts +1 -1
  183. package/dist/types/compute-engine/library/collections.d.ts +1 -1
  184. package/dist/types/compute-engine/library/colors.d.ts +1 -1
  185. package/dist/types/compute-engine/library/combinatorics.d.ts +1 -1
  186. package/dist/types/compute-engine/library/complex.d.ts +13 -1
  187. package/dist/types/compute-engine/library/control-structures.d.ts +1 -1
  188. package/dist/types/compute-engine/library/core.d.ts +1 -1
  189. package/dist/types/compute-engine/library/fractals.d.ts +1 -1
  190. package/dist/types/compute-engine/library/library.d.ts +1 -1
  191. package/dist/types/compute-engine/library/linear-algebra.d.ts +1 -1
  192. package/dist/types/compute-engine/library/logic-analysis.d.ts +1 -1
  193. package/dist/types/compute-engine/library/logic.d.ts +1 -1
  194. package/dist/types/compute-engine/library/number-theory.d.ts +1 -1
  195. package/dist/types/compute-engine/library/polynomials.d.ts +1 -1
  196. package/dist/types/compute-engine/library/quantity-arithmetic.d.ts +1 -1
  197. package/dist/types/compute-engine/library/random-expression.d.ts +1 -1
  198. package/dist/types/compute-engine/library/relational-operator.d.ts +1 -1
  199. package/dist/types/compute-engine/library/sets.d.ts +27 -1
  200. package/dist/types/compute-engine/library/statistics.d.ts +1 -1
  201. package/dist/types/compute-engine/library/trigonometry.d.ts +1 -1
  202. package/dist/types/compute-engine/library/type-handlers.d.ts +1 -1
  203. package/dist/types/compute-engine/library/unit-data.d.ts +1 -1
  204. package/dist/types/compute-engine/library/units.d.ts +1 -1
  205. package/dist/types/compute-engine/library/utils.d.ts +1 -1
  206. package/dist/types/compute-engine/numeric-value/big-numeric-value.d.ts +1 -1
  207. package/dist/types/compute-engine/numeric-value/exact-numeric-value.d.ts +7 -1
  208. package/dist/types/compute-engine/numeric-value/machine-numeric-value.d.ts +1 -1
  209. package/dist/types/compute-engine/numeric-value/types.d.ts +1 -1
  210. package/dist/types/compute-engine/numerics/bernoulli.d.ts +39 -0
  211. package/dist/types/compute-engine/numerics/bigint.d.ts +1 -1
  212. package/dist/types/compute-engine/numerics/expression.d.ts +1 -1
  213. package/dist/types/compute-engine/numerics/interval.d.ts +1 -1
  214. package/dist/types/compute-engine/numerics/linear-algebra.d.ts +1 -1
  215. package/dist/types/compute-engine/numerics/monte-carlo.d.ts +1 -1
  216. package/dist/types/compute-engine/numerics/numeric-bigint.d.ts +1 -1
  217. package/dist/types/compute-engine/numerics/numeric-bignum.d.ts +1 -1
  218. package/dist/types/compute-engine/numerics/numeric-complex.d.ts +12 -1
  219. package/dist/types/compute-engine/numerics/numeric.d.ts +1 -1
  220. package/dist/types/compute-engine/numerics/primes.d.ts +1 -1
  221. package/dist/types/compute-engine/numerics/random.d.ts +23 -0
  222. package/dist/types/compute-engine/numerics/rationals.d.ts +1 -1
  223. package/dist/types/compute-engine/numerics/richardson.d.ts +1 -1
  224. package/dist/types/compute-engine/numerics/special-functions.d.ts +78 -10
  225. package/dist/types/compute-engine/numerics/statistics.d.ts +1 -1
  226. package/dist/types/compute-engine/numerics/strings.d.ts +1 -1
  227. package/dist/types/compute-engine/numerics/types.d.ts +1 -1
  228. package/dist/types/compute-engine/numerics/unit-data.d.ts +1 -1
  229. package/dist/types/compute-engine/oeis.d.ts +1 -1
  230. package/dist/types/compute-engine/sequence.d.ts +1 -1
  231. package/dist/types/compute-engine/symbolic/antiderivative.d.ts +1 -1
  232. package/dist/types/compute-engine/symbolic/derivative.d.ts +1 -1
  233. package/dist/types/compute-engine/symbolic/distribute.d.ts +1 -1
  234. package/dist/types/compute-engine/symbolic/fu-cost.d.ts +1 -1
  235. package/dist/types/compute-engine/symbolic/fu-transforms.d.ts +1 -1
  236. package/dist/types/compute-engine/symbolic/fu.d.ts +1 -1
  237. package/dist/types/compute-engine/symbolic/logic-utils.d.ts +1 -1
  238. package/dist/types/compute-engine/symbolic/simplify-abs.d.ts +1 -1
  239. package/dist/types/compute-engine/symbolic/simplify-divide.d.ts +1 -1
  240. package/dist/types/compute-engine/symbolic/simplify-factorial.d.ts +1 -1
  241. package/dist/types/compute-engine/symbolic/simplify-hyperbolic.d.ts +1 -1
  242. package/dist/types/compute-engine/symbolic/simplify-infinity.d.ts +1 -1
  243. package/dist/types/compute-engine/symbolic/simplify-log.d.ts +1 -1
  244. package/dist/types/compute-engine/symbolic/simplify-logic.d.ts +1 -1
  245. package/dist/types/compute-engine/symbolic/simplify-power.d.ts +1 -1
  246. package/dist/types/compute-engine/symbolic/simplify-product.d.ts +1 -1
  247. package/dist/types/compute-engine/symbolic/simplify-rules.d.ts +1 -1
  248. package/dist/types/compute-engine/symbolic/simplify-sum.d.ts +1 -1
  249. package/dist/types/compute-engine/symbolic/simplify-trig.d.ts +1 -1
  250. package/dist/types/compute-engine/tensor/tensor-fields.d.ts +1 -1
  251. package/dist/types/compute-engine/tensor/tensors.d.ts +3 -3
  252. package/dist/types/compute-engine/types-definitions.d.ts +1 -1
  253. package/dist/types/compute-engine/types-engine.d.ts +52 -3
  254. package/dist/types/compute-engine/types-evaluation.d.ts +1 -1
  255. package/dist/types/compute-engine/types-expression.d.ts +85 -14
  256. package/dist/types/compute-engine/types-kernel-evaluation.d.ts +32 -1
  257. package/dist/types/compute-engine/types-kernel-serialization.d.ts +45 -3
  258. package/dist/types/compute-engine/types-serialization.d.ts +1 -1
  259. package/dist/types/compute-engine/types.d.ts +1 -1
  260. package/dist/types/compute-engine.d.ts +1 -1
  261. package/dist/types/core.d.ts +1 -1
  262. package/dist/types/identities.d.ts +3 -0
  263. package/dist/types/interval.d.ts +1 -1
  264. package/dist/types/latex-syntax.d.ts +2 -2
  265. package/dist/types/math-json/symbols.d.ts +1 -1
  266. package/dist/types/math-json/types.d.ts +1 -1
  267. package/dist/types/math-json/utils.d.ts +1 -1
  268. package/dist/types/math-json.d.ts +2 -2
  269. package/dist/types/numerics.d.ts +1 -1
  270. package/package.json +9 -3
@@ -1,4 +1,4 @@
1
- /** Compile 0.57.0 */
1
+ /** Compile 0.59.0 */
2
2
  (function(global,factory){typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'],factory):(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Compile = {}));})(this, (function (exports) { 'use strict';
3
3
  var Compile = (() => {
4
4
  var __defProp = Object.defineProperty;
@@ -192,6 +192,7 @@ var Compile = (() => {
192
192
  return sum;
193
193
  }
194
194
  function fpln(x, scale) {
195
+ if (x <= 0n) throw new RangeError("fpln: input must be positive");
195
196
  if (x === scale) return 0n;
196
197
  const xNum = Number(x);
197
198
  const scaleNum = Number(scale);
@@ -841,9 +842,11 @@ var Compile = (() => {
841
842
  if (Number.isFinite(thisExp) && Number.isFinite(otherExp)) {
842
843
  if (other.significand === 0n) return _BigDecimal.NAN;
843
844
  if (this.significand === 0n) return fromRaw(0n, 0);
844
- return this.sub(this.div(other).trunc().mul(other)).toPrecision(
845
- _BigDecimal.precision
846
- );
845
+ const ediff = thisExp - otherExp;
846
+ const num = ediff >= 0 ? this.significand * pow10(ediff) : this.significand;
847
+ const den = ediff >= 0 ? other.significand : other.significand * pow10(-ediff);
848
+ const q = num / den;
849
+ return this.sub(fromRaw(q, 0).mul(other));
847
850
  }
848
851
  if (thisExp !== thisExp || otherExp !== otherExp) return _BigDecimal.NAN;
849
852
  if (!Number.isFinite(thisExp)) return _BigDecimal.NAN;
@@ -888,7 +891,10 @@ var Compile = (() => {
888
891
  return this.pow(n.neg()).inv();
889
892
  }
890
893
  const absSig = this.significand < 0n ? -this.significand : this.significand;
891
- const thisLog10 = bigintDigits(absSig) + this.exponent;
894
+ const sigDigits = bigintDigits(absSig);
895
+ const dropped = sigDigits > 15 ? sigDigits - 15 : 0;
896
+ const lead = dropped > 0 ? Number(absSig / 10n ** BigInt(dropped)) : Number(absSig);
897
+ const thisLog10 = Math.log10(lead) + dropped + this.exponent;
892
898
  const resultLog10 = Number(expValue) * thisLog10;
893
899
  if (resultLog10 > 9e15) {
894
900
  return this.significand < 0n && expValue % 2n !== 0n ? _BigDecimal.NEGATIVE_INFINITY : _BigDecimal.POSITIVE_INFINITY;
@@ -921,7 +927,19 @@ var Compile = (() => {
921
927
  return _BigDecimal.POSITIVE_INFINITY;
922
928
  }
923
929
  if (this.significand < 0n) return _BigDecimal.NAN;
924
- return n.mul(this.ln()).exp();
930
+ const baseSig = this.significand;
931
+ const decExpBase = this.exponent + bigintDigits(baseSig) - 1;
932
+ const nSig = n.significand < 0n ? -n.significand : n.significand;
933
+ const decExpN = n.exponent + bigintDigits(nSig) - 1;
934
+ const argMag = decExpN + Math.log10(Math.abs(decExpBase) * 2.303 + 3) + 1;
935
+ const extra = Math.min(20, Math.max(2, Math.ceil(argMag) + 2));
936
+ const savedPrec = _BigDecimal.precision;
937
+ _BigDecimal.precision = savedPrec + extra;
938
+ try {
939
+ return n.mul(this.ln()).exp().toPrecision(savedPrec);
940
+ } finally {
941
+ _BigDecimal.precision = savedPrec;
942
+ }
925
943
  }
926
944
  // ---------- Conversion methods ----------
927
945
  /** Convert to a JavaScript number. May lose precision for large values. */
@@ -1162,6 +1180,20 @@ var Compile = (() => {
1162
1180
  const sig = negative ? -absFp : absFp;
1163
1181
  return fromRaw(sig, resultExp);
1164
1182
  }
1183
+ function decimalExponent(x) {
1184
+ const sig = x.significand < 0n ? -x.significand : x.significand;
1185
+ return x.exponent + bigintDigits(sig) - 1;
1186
+ }
1187
+ var MAX_SAFE_EXPONENT = BigInt(Number.MAX_SAFE_INTEGER);
1188
+ var _ln10Fp = null;
1189
+ var _ln10Scale = null;
1190
+ function ln10Fixed(scale) {
1191
+ if (_ln10Scale !== scale) {
1192
+ _ln10Fp = fpln(10n * scale, scale);
1193
+ _ln10Scale = scale;
1194
+ }
1195
+ return _ln10Fp;
1196
+ }
1165
1197
  BigDecimal.prototype.sqrt = function() {
1166
1198
  if (this.isNaN()) return BigDecimal.NAN;
1167
1199
  if (this.isZero()) return BigDecimal.ZERO;
@@ -1172,9 +1204,13 @@ var Compile = (() => {
1172
1204
  if (this.significand < 0n) return BigDecimal.NAN;
1173
1205
  const targetPrec = BigDecimal.precision;
1174
1206
  const workingPrec = targetPrec + 10;
1175
- const [fp, scale] = toFixedPoint(this, workingPrec);
1207
+ const e = decimalExponent(this);
1208
+ const k = Math.floor(e / 2);
1209
+ const m = fromRaw(this.significand, this.exponent - 2 * k);
1210
+ const [fp, scale] = toFixedPoint(m, workingPrec);
1176
1211
  const sqrtFp = fpsqrt(fp, scale);
1177
- return fromFixedPoint(sqrtFp, scale, targetPrec);
1212
+ const root = fromFixedPoint(sqrtFp, scale, targetPrec);
1213
+ return fromRaw(root.significand, root.exponent + k);
1178
1214
  };
1179
1215
  BigDecimal.prototype.cbrt = function() {
1180
1216
  if (this.isNaN()) return BigDecimal.NAN;
@@ -1188,10 +1224,13 @@ var Compile = (() => {
1188
1224
  }
1189
1225
  const targetPrec = BigDecimal.precision;
1190
1226
  const workingPrec = targetPrec + 10;
1191
- const [fp, scale] = toFixedPoint(this, workingPrec);
1227
+ const e = decimalExponent(this);
1228
+ const k = Math.floor(e / 3);
1229
+ const m = fromRaw(this.significand, this.exponent - 3 * k);
1230
+ const [fp, scale] = toFixedPoint(m, workingPrec);
1192
1231
  const C = fp * scale * scale;
1193
1232
  let x;
1194
- const numVal = this.toNumber();
1233
+ const numVal = m.toNumber();
1195
1234
  const scaleNum = Number(scale);
1196
1235
  if (Number.isFinite(numVal) && numVal > 0 && Number.isFinite(scaleNum)) {
1197
1236
  const approx = Math.cbrt(numVal);
@@ -1220,7 +1259,8 @@ var Compile = (() => {
1220
1259
  const diffNext = bigintAbs(next * next * next - C);
1221
1260
  if (diffNext < diffX) x = next;
1222
1261
  }
1223
- return fromFixedPoint(x, scale, targetPrec);
1262
+ const root = fromFixedPoint(x, scale, targetPrec);
1263
+ return fromRaw(root.significand, root.exponent + k);
1224
1264
  };
1225
1265
  BigDecimal.sqrt = function(x) {
1226
1266
  return x.sqrt();
@@ -1235,11 +1275,27 @@ var Compile = (() => {
1235
1275
  return BigDecimal.ZERO;
1236
1276
  }
1237
1277
  if (this.isZero()) return BigDecimal.ONE;
1278
+ if (decimalExponent(this) >= 17)
1279
+ return this.significand > 0n ? BigDecimal.POSITIVE_INFINITY : BigDecimal.ZERO;
1238
1280
  const targetPrec = BigDecimal.precision;
1239
- const workingPrec = targetPrec + 15;
1240
- const [fp, scale] = toFixedPoint(this, workingPrec);
1241
- const expFp = fpexp(fp, scale);
1242
- return fromFixedPoint(expFp, scale, targetPrec);
1281
+ const absSig = this.significand < 0n ? -this.significand : this.significand;
1282
+ const magnitude = Math.max(0, this.exponent + bigintDigits(absSig));
1283
+ const workingPrec = targetPrec + 20 + magnitude;
1284
+ const [xFp, scale] = toFixedPoint(this, workingPrec);
1285
+ const l10 = ln10Fixed(scale);
1286
+ let k = xFp / l10;
1287
+ let rFp = xFp - k * l10;
1288
+ if (rFp < 0n) {
1289
+ k -= 1n;
1290
+ rFp += l10;
1291
+ }
1292
+ if (k > MAX_SAFE_EXPONENT || k < -MAX_SAFE_EXPONENT)
1293
+ return k > 0n ? BigDecimal.POSITIVE_INFINITY : BigDecimal.ZERO;
1294
+ const expR = fromFixedPoint(fpexp(rFp, scale), scale, targetPrec);
1295
+ const newExp = expR.exponent + Number(k);
1296
+ if (!Number.isSafeInteger(newExp))
1297
+ return k > 0n ? BigDecimal.POSITIVE_INFINITY : BigDecimal.ZERO;
1298
+ return fromRaw(expR.significand, newExp);
1243
1299
  };
1244
1300
  BigDecimal.prototype.ln = function() {
1245
1301
  if (this.isNaN()) return BigDecimal.NAN;
@@ -1251,10 +1307,16 @@ var Compile = (() => {
1251
1307
  if (this.significand < 0n) return BigDecimal.NAN;
1252
1308
  if (this.eq(1)) return BigDecimal.ZERO;
1253
1309
  const targetPrec = BigDecimal.precision;
1254
- const workingPrec = targetPrec + 15;
1255
- const [fp, scale] = toFixedPoint(this, workingPrec);
1256
- const lnFp = fpln(fp, scale);
1257
- return fromFixedPoint(lnFp, scale, targetPrec);
1310
+ const sig = this.significand;
1311
+ const digits = bigintDigits(sig);
1312
+ const e = this.exponent + digits - 1;
1313
+ const m = fromRaw(sig, -(digits - 1));
1314
+ const eDigits = Math.abs(e).toString().length;
1315
+ const workingPrec = targetPrec + 20 + eDigits;
1316
+ const [mFp, scale] = toFixedPoint(m, workingPrec);
1317
+ const l10 = ln10Fixed(scale);
1318
+ const resultFp = fpln(mFp, scale) + BigInt(e) * l10;
1319
+ return fromFixedPoint(resultFp, scale, targetPrec);
1258
1320
  };
1259
1321
  BigDecimal.prototype.log = function(base) {
1260
1322
  const b = base instanceof BigDecimal ? base : new BigDecimal(base);
@@ -1274,7 +1336,10 @@ var Compile = (() => {
1274
1336
  if (!this.isFinite()) return BigDecimal.NAN;
1275
1337
  if (this.isZero()) return BigDecimal.ZERO;
1276
1338
  const targetPrec = BigDecimal.precision;
1277
- const workingPrec = targetPrec + 15;
1339
+ const e = decimalExponent(this);
1340
+ if (e < 0 && -2 * e >= targetPrec + 4) return this.toPrecision(targetPrec);
1341
+ const workingPrec = targetPrec + 15 + (e < 0 ? -e : 0);
1342
+ if (e > PI_DIGITS.length - workingPrec - 30) return BigDecimal.NAN;
1278
1343
  const [fp, scale] = toFixedPoint(this, workingPrec);
1279
1344
  const [sinFp] = fpsincos(fp, scale);
1280
1345
  return fromFixedPoint(sinFp, scale, targetPrec);
@@ -1285,6 +1350,8 @@ var Compile = (() => {
1285
1350
  if (this.isZero()) return BigDecimal.ONE;
1286
1351
  const targetPrec = BigDecimal.precision;
1287
1352
  const workingPrec = targetPrec + 15;
1353
+ const e = decimalExponent(this);
1354
+ if (e > PI_DIGITS.length - workingPrec - 30) return BigDecimal.NAN;
1288
1355
  const [fp, scale] = toFixedPoint(this, workingPrec);
1289
1356
  const [, cosFp] = fpsincos(fp, scale);
1290
1357
  return fromFixedPoint(cosFp, scale, targetPrec);
@@ -1294,7 +1361,10 @@ var Compile = (() => {
1294
1361
  if (!this.isFinite()) return BigDecimal.NAN;
1295
1362
  if (this.isZero()) return BigDecimal.ZERO;
1296
1363
  const targetPrec = BigDecimal.precision;
1297
- const workingPrec = targetPrec + 15;
1364
+ const e = decimalExponent(this);
1365
+ if (e < 0 && -2 * e >= targetPrec + 4) return this.toPrecision(targetPrec);
1366
+ const workingPrec = targetPrec + 15 + (e < 0 ? -e : 0);
1367
+ if (e > PI_DIGITS.length - workingPrec - 30) return BigDecimal.NAN;
1298
1368
  const [fp, scale] = toFixedPoint(this, workingPrec);
1299
1369
  const [sinFp, cosFp] = fpsincos(fp, scale);
1300
1370
  if (cosFp === 0n) {
@@ -1312,7 +1382,9 @@ var Compile = (() => {
1312
1382
  return piHalf.neg();
1313
1383
  }
1314
1384
  const targetPrec = BigDecimal.precision;
1315
- const workingPrec = targetPrec + 15;
1385
+ const e = decimalExponent(this);
1386
+ if (e < 0 && -2 * e >= targetPrec + 4) return this.toPrecision(targetPrec);
1387
+ const workingPrec = targetPrec + 15 + (e < 0 ? -e : 0);
1316
1388
  const [fp, scale] = toFixedPoint(this, workingPrec);
1317
1389
  const atanFp = fpatan(fp, scale);
1318
1390
  return fromFixedPoint(atanFp, scale, targetPrec);
@@ -1329,7 +1401,9 @@ var Compile = (() => {
1329
1401
  return this.significand > 0n ? piHalf : piHalf.neg();
1330
1402
  }
1331
1403
  const targetPrec = BigDecimal.precision;
1332
- const workingPrec = targetPrec + 20;
1404
+ const e = decimalExponent(this);
1405
+ if (e < 0 && -2 * e >= targetPrec + 4) return this.toPrecision(targetPrec);
1406
+ const workingPrec = targetPrec + 20 + (e < 0 ? -e : 0);
1333
1407
  const [xFp, scale] = toFixedPoint(this, workingPrec);
1334
1408
  const x2 = fpmul(xFp, xFp, scale);
1335
1409
  const oneMinusX2 = scale - x2;
@@ -1392,6 +1466,23 @@ var Compile = (() => {
1392
1466
  if (this.significand > 0n) return BigDecimal.POSITIVE_INFINITY;
1393
1467
  return BigDecimal.NEGATIVE_INFINITY;
1394
1468
  }
1469
+ const targetPrec = BigDecimal.precision;
1470
+ const e = decimalExponent(this);
1471
+ if (e < 0) {
1472
+ if (-2 * e >= targetPrec + 4) return this.toPrecision(targetPrec);
1473
+ const saved = BigDecimal.precision;
1474
+ BigDecimal.precision = targetPrec - e + 5;
1475
+ try {
1476
+ const expX2 = this.exp();
1477
+ return expX2.sub(expX2.inv()).div(BigDecimal.TWO).toPrecision(targetPrec);
1478
+ } finally {
1479
+ BigDecimal.precision = saved;
1480
+ }
1481
+ }
1482
+ if (Math.abs(this.toNumber()) > 1.16 * (targetPrec + 3)) {
1483
+ const h = this.abs().exp().div(BigDecimal.TWO);
1484
+ return this.significand > 0n ? h : h.neg();
1485
+ }
1395
1486
  const expX = this.exp();
1396
1487
  const expNegX = expX.inv();
1397
1488
  return expX.sub(expNegX).div(BigDecimal.TWO);
@@ -1402,6 +1493,9 @@ var Compile = (() => {
1402
1493
  if (!this.isFinite()) {
1403
1494
  return BigDecimal.POSITIVE_INFINITY;
1404
1495
  }
1496
+ const targetPrec = BigDecimal.precision;
1497
+ if (Math.abs(this.toNumber()) > 1.16 * (targetPrec + 3))
1498
+ return this.abs().exp().div(BigDecimal.TWO);
1405
1499
  const expX = this.exp();
1406
1500
  const expNegX = expX.inv();
1407
1501
  return expX.add(expNegX).div(BigDecimal.TWO);
@@ -1413,6 +1507,21 @@ var Compile = (() => {
1413
1507
  if (this.significand > 0n) return BigDecimal.ONE;
1414
1508
  return BigDecimal.NEGATIVE_ONE;
1415
1509
  }
1510
+ const targetPrec = BigDecimal.precision;
1511
+ const e = decimalExponent(this);
1512
+ if (e < 0) {
1513
+ if (-2 * e >= targetPrec + 4) return this.toPrecision(targetPrec);
1514
+ const saved = BigDecimal.precision;
1515
+ BigDecimal.precision = targetPrec - e + 5;
1516
+ try {
1517
+ const exp2x2 = this.mul(BigDecimal.TWO).exp();
1518
+ return exp2x2.sub(BigDecimal.ONE).div(exp2x2.add(BigDecimal.ONE)).toPrecision(targetPrec);
1519
+ } finally {
1520
+ BigDecimal.precision = saved;
1521
+ }
1522
+ }
1523
+ if (Math.abs(this.toNumber()) > 1.16 * (targetPrec + 3))
1524
+ return this.significand > 0n ? BigDecimal.ONE : BigDecimal.NEGATIVE_ONE;
1416
1525
  const exp2x = this.mul(BigDecimal.TWO).exp();
1417
1526
  return exp2x.sub(BigDecimal.ONE).div(exp2x.add(BigDecimal.ONE));
1418
1527
  };
@@ -1461,6 +1570,7 @@ var Compile = (() => {
1461
1570
  Math.log10(Math.pow(2, MACHINE_PRECISION_BITS))
1462
1571
  );
1463
1572
  var DEFAULT_TOLERANCE = 1e-10;
1573
+ var SMALL_INTEGER = 1e6;
1464
1574
  var MAX_ITERATION = 1e4;
1465
1575
  function gcd(a, b) {
1466
1576
  if (a === 0) return b;
@@ -1472,7 +1582,8 @@ var Compile = (() => {
1472
1582
  }
1473
1583
  function lcm(a, b) {
1474
1584
  if (a === 0 || b === 0) return 0;
1475
- const res = BigInt(a) * BigInt(b) / BigInt(gcd(a, b));
1585
+ let res = BigInt(a) * BigInt(b) / BigInt(gcd(a, b));
1586
+ if (res < 0n) res = -res;
1476
1587
  return Number(res);
1477
1588
  }
1478
1589
  function factorial(n) {
@@ -1562,216 +1673,27 @@ var Compile = (() => {
1562
1673
  "error",
1563
1674
  ...EXPRESSION_TYPES
1564
1675
  ];
1676
+ var NUMERIC_TYPES_SET = new Set(
1677
+ NUMERIC_TYPES
1678
+ );
1679
+ var COLLECTION_TYPES_SET = new Set(
1680
+ COLLECTION_TYPES
1681
+ );
1682
+ var SCALAR_TYPES_SET = new Set(
1683
+ SCALAR_TYPES
1684
+ );
1685
+ var PRIMITIVE_TYPES_SET = new Set(
1686
+ PRIMITIVE_TYPES
1687
+ );
1688
+ function isValidPrimitiveType(s) {
1689
+ if (typeof s !== "string") return false;
1690
+ return PRIMITIVE_TYPES_SET.has(s);
1691
+ }
1565
1692
  function isValidType(t) {
1566
- if (typeof t === "string")
1567
- return PRIMITIVE_TYPES.includes(t);
1693
+ if (typeof t === "string") return PRIMITIVE_TYPES_SET.has(t);
1568
1694
  if (typeof t !== "object") return false;
1569
1695
  if (!("kind" in t)) return false;
1570
- return t.kind === "signature" || t.kind === "union" || t.kind === "intersection" || t.kind === "negation" || t.kind === "tuple" || t.kind === "list" || t.kind === "record" || t.kind === "dictionary" || t.kind === "set" || t.kind === "function" || t.kind === "collection" || t.kind === "indexed_collection" || t.kind === "reference";
1571
- }
1572
-
1573
- // src/common/type/serialize.ts
1574
- var NEGATION_PRECEDENCE = 3;
1575
- var UNION_PRECEDENCE = 1;
1576
- var INTERSECTION_PRECEDENCE = 2;
1577
- var LIST_PRECEDENCE = 4;
1578
- var RECORD_PRECEDENCE = 5;
1579
- var DICTIONARY_PRECEDENCE = 6;
1580
- var SET_PRECEDENCE = 7;
1581
- var COLLECTION_PRECEDENCE = 8;
1582
- var TUPLE_PRECEDENCE = 9;
1583
- var SIGNATURE_PRECEDENCE = 10;
1584
- var VALUE_PRECEDENCE = 11;
1585
- function typeToString(type, precedence = 0) {
1586
- if (typeof type === "string") return type;
1587
- let result = "";
1588
- switch (type.kind) {
1589
- case "value":
1590
- if (typeof type.value === "string") result = `"${type.value}"`;
1591
- else if (typeof type.value === "boolean")
1592
- result = type.value ? "true" : "false";
1593
- else result = type.value.toString();
1594
- break;
1595
- case "reference":
1596
- result = type.name;
1597
- break;
1598
- case "negation":
1599
- result = `!${typeToString(type.type, NEGATION_PRECEDENCE)}`;
1600
- break;
1601
- case "union":
1602
- result = type.types.map((t) => typeToString(t, UNION_PRECEDENCE)).join(" | ");
1603
- break;
1604
- case "intersection":
1605
- result = type.types.map((t) => typeToString(t, INTERSECTION_PRECEDENCE)).join(" & ");
1606
- break;
1607
- case "expression":
1608
- result = `expression<${symbolName(type.operator)}>`;
1609
- break;
1610
- case "symbol":
1611
- result = `symbol<${symbolName(type.name)}>`;
1612
- break;
1613
- case "numeric":
1614
- if (Number.isFinite(type.lower) && Number.isFinite(type.upper)) {
1615
- result = `${type.type}<${type.lower}..${type.upper}>`;
1616
- } else if (Number.isFinite(type.lower)) {
1617
- result = `${type.type}<${type.lower}..>`;
1618
- } else if (Number.isFinite(type.upper)) {
1619
- result = `${type.type}<..${type.upper}>`;
1620
- } else {
1621
- result = `${type.type}`;
1622
- }
1623
- break;
1624
- case "list":
1625
- if (type.dimensions && typeof type.elements === "string" && NUMERIC_TYPES.includes(type.elements)) {
1626
- if (type.dimensions === void 0) {
1627
- if (type.elements === "number") result = "tensor";
1628
- } else if (type.dimensions.length === 1) {
1629
- if (type.elements === "number") {
1630
- if (type.dimensions[0] < 0) result = "vector";
1631
- else result = `vector<${type.dimensions[0]}>`;
1632
- } else {
1633
- if (type.dimensions[0] < 0)
1634
- result = `vector<${typeToString(type.elements)}>`;
1635
- else
1636
- result = `vector<${typeToString(type.elements)}^${type.dimensions[0]}>`;
1637
- }
1638
- } else if (type.dimensions.length === 2) {
1639
- const dims = type.dimensions;
1640
- if (type.elements === "number") {
1641
- if (dims[0] < 0 && dims[1] < 0) result = "matrix";
1642
- else result = `matrix<${dims[0]}x${dims[1]}>`;
1643
- } else {
1644
- if (dims[0] < 0 && dims[1] < 0)
1645
- result = `matrix<${typeToString(type.elements)}>`;
1646
- else
1647
- result = `matrix<${typeToString(type.elements)}^(${dims[0]}x${dims[1]})>`;
1648
- }
1649
- }
1650
- }
1651
- if (!result) {
1652
- const dimensions = type.dimensions ? type.dimensions.length === 1 ? `^${type.dimensions[0].toString()}` : `^(${type.dimensions.join("x")})` : "";
1653
- result = `list<${typeToString(type.elements)}${dimensions}>`;
1654
- }
1655
- break;
1656
- case "record":
1657
- const elements = Object.entries(type.elements).map(([key, value]) => `${key}: ${typeToString(value)}`).join(", ");
1658
- result = `record<${elements}>`;
1659
- break;
1660
- case "dictionary":
1661
- result = `dictionary<${typeToString(type.values)}>`;
1662
- break;
1663
- case "set":
1664
- result = `set<${typeToString(type.elements)}>`;
1665
- break;
1666
- case "collection":
1667
- result = `collection<${typeToString(type.elements)}>`;
1668
- break;
1669
- case "indexed_collection":
1670
- result = `indexed_collection<${typeToString(type.elements)}>`;
1671
- break;
1672
- case "tuple":
1673
- if (type.elements.length === 0) result = "tuple";
1674
- else if (type.elements.length === 1) {
1675
- const [el] = type.elements;
1676
- result = `tuple<${namedElement(el)}>`;
1677
- } else {
1678
- result = "tuple<" + type.elements.map((el) => namedElement(el)).join(", ") + ">";
1679
- }
1680
- break;
1681
- case "signature":
1682
- const args = type.args ? type.args.map((arg) => namedElement(arg)).join(", ") : "";
1683
- const optArgs = type.optArgs ? type.optArgs.map((arg) => namedElement(arg) + "?").join(", ") : "";
1684
- const varArg = type.variadicArg ? type.variadicMin === 0 ? `${namedElement(type.variadicArg)}*` : `${namedElement(type.variadicArg)}+` : "";
1685
- const argsList = [args, optArgs, varArg].filter((s) => s).join(", ");
1686
- result = `(${argsList}) -> ${typeToString(type.result)}`;
1687
- break;
1688
- default:
1689
- result = "error";
1690
- }
1691
- if (precedence > 0 && precedence > getPrecedence(type.kind))
1692
- return `(${result})`;
1693
- return result;
1694
- }
1695
- function namedElement(el) {
1696
- if (el.name) return `${el.name}: ${typeToString(el.type)}`;
1697
- return typeToString(el.type);
1698
- }
1699
- function symbolName(name) {
1700
- if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) return name;
1701
- return `\`${name}\``;
1702
- }
1703
- function getPrecedence(kind) {
1704
- switch (kind) {
1705
- case "negation":
1706
- return NEGATION_PRECEDENCE;
1707
- case "union":
1708
- return UNION_PRECEDENCE;
1709
- case "intersection":
1710
- return INTERSECTION_PRECEDENCE;
1711
- case "list":
1712
- return LIST_PRECEDENCE;
1713
- case "record":
1714
- return RECORD_PRECEDENCE;
1715
- case "dictionary":
1716
- return DICTIONARY_PRECEDENCE;
1717
- case "set":
1718
- return SET_PRECEDENCE;
1719
- case "collection":
1720
- case "indexed_collection":
1721
- return COLLECTION_PRECEDENCE;
1722
- case "tuple":
1723
- return TUPLE_PRECEDENCE;
1724
- case "signature":
1725
- return SIGNATURE_PRECEDENCE;
1726
- case "value":
1727
- return VALUE_PRECEDENCE;
1728
- default:
1729
- return 0;
1730
- }
1731
- }
1732
-
1733
- // src/common/fuzzy-string-match.ts
1734
- function levenshtein(source, target) {
1735
- if (source === target) return 0;
1736
- if (source.length === 0) return target.length;
1737
- if (target.length === 0) return source.length;
1738
- let prevRow = Array.from(
1739
- { length: source.length + 1 },
1740
- (_, j) => j
1741
- );
1742
- let currRow = new Array(source.length + 1);
1743
- for (let i = 1; i <= target.length; i++) {
1744
- currRow[0] = i;
1745
- for (let j = 1; j <= source.length; j++) {
1746
- const cost = source[j - 1] === target[i - 1] ? 0 : 1;
1747
- currRow[j] = Math.min(
1748
- prevRow[j] + 1,
1749
- // deletion
1750
- currRow[j - 1] + 1,
1751
- // insertion
1752
- prevRow[j - 1] + cost
1753
- // substitution
1754
- );
1755
- }
1756
- [prevRow, currRow] = [currRow, prevRow];
1757
- }
1758
- return prevRow[source.length];
1759
- }
1760
- function fuzzyStringMatch(invalidWord, validWords) {
1761
- const threshold = 7;
1762
- let bestMatch = null;
1763
- let minDistance = Infinity;
1764
- const invalidLength = invalidWord.length;
1765
- for (const word of validWords) {
1766
- if (Math.abs(invalidLength - word.length) > threshold) continue;
1767
- const distance = levenshtein(invalidWord, word);
1768
- if (distance === 0) return word;
1769
- if (distance <= threshold && distance < minDistance) {
1770
- minDistance = distance;
1771
- bestMatch = word;
1772
- }
1773
- }
1774
- return bestMatch;
1696
+ return t.kind === "signature" || t.kind === "union" || t.kind === "intersection" || t.kind === "negation" || t.kind === "value" || t.kind === "tuple" || t.kind === "list" || t.kind === "record" || t.kind === "dictionary" || t.kind === "set" || t.kind === "symbol" || t.kind === "expression" || t.kind === "numeric" || t.kind === "collection" || t.kind === "indexed_collection" || t.kind === "reference";
1775
1697
  }
1776
1698
 
1777
1699
  // src/common/type/lexer.ts
@@ -2481,19 +2403,13 @@ var Compile = (() => {
2481
2403
  );
2482
2404
  let dimensions;
2483
2405
  if (this.match("<")) {
2484
- dimensions = this.parseDimensionWithX();
2485
- if (!dimensions) {
2486
- dimensions = this.parseDimensions();
2487
- }
2406
+ dimensions = this.parseDimensions();
2488
2407
  if (!dimensions) {
2489
2408
  const type = this.parseUnionType();
2490
2409
  if (type) {
2491
2410
  elementType = type;
2492
2411
  if (this.match("^")) {
2493
- dimensions = this.parseDimensionWithX();
2494
- if (!dimensions) {
2495
- dimensions = this.parseDimensions();
2496
- }
2412
+ dimensions = this.parseCaretDimensions();
2497
2413
  }
2498
2414
  }
2499
2415
  }
@@ -2534,19 +2450,13 @@ var Compile = (() => {
2534
2450
  );
2535
2451
  let dimensions;
2536
2452
  if (this.match("<")) {
2537
- dimensions = this.parseDimensionWithX();
2538
- if (!dimensions) {
2539
- dimensions = this.parseDimensions();
2540
- }
2453
+ dimensions = this.parseDimensions();
2541
2454
  if (!dimensions) {
2542
2455
  const type = this.parseUnionType();
2543
2456
  if (type) {
2544
2457
  elementType = type;
2545
2458
  if (this.match("^")) {
2546
- dimensions = this.parseDimensionWithX();
2547
- if (!dimensions) {
2548
- dimensions = this.parseDimensions();
2549
- }
2459
+ dimensions = this.parseCaretDimensions();
2550
2460
  }
2551
2461
  }
2552
2462
  }
@@ -2577,16 +2487,30 @@ var Compile = (() => {
2577
2487
  return this.createNode("tensor", { elementType });
2578
2488
  }
2579
2489
  parseDimensions() {
2580
- const dimensions = [];
2581
2490
  const firstDim = this.parseDimension();
2582
2491
  if (!firstDim) return void 0;
2583
- dimensions.push(firstDim);
2584
- while (this.match("x")) {
2585
- const dim = this.parseDimension();
2586
- if (!dim) {
2587
- this.error("Expected dimension after x");
2492
+ const dimensions = [firstDim];
2493
+ for (; ; ) {
2494
+ const tok = this.current;
2495
+ if (tok.type === "IDENTIFIER" && /^(x\d+)+$/.test(tok.value)) {
2496
+ this.advance();
2497
+ for (const m of tok.value.match(/x(\d+)/g))
2498
+ dimensions.push(
2499
+ this.createNode("dimension", {
2500
+ size: parseInt(m.slice(1))
2501
+ })
2502
+ );
2503
+ } else if (tok.type === "IDENTIFIER" && tok.value === "x") {
2504
+ const next = this.lexer.peekToken();
2505
+ if (next.type !== "NUMBER_LITERAL" && next.type !== "?")
2506
+ this.error(
2507
+ "Expected a positive integer literal or `?` after x. For example: `2x3` or `2x?`"
2508
+ );
2509
+ this.advance();
2510
+ dimensions.push(this.parseDimension());
2511
+ } else {
2512
+ break;
2588
2513
  }
2589
- dimensions.push(dim);
2590
2514
  }
2591
2515
  return dimensions;
2592
2516
  }
@@ -2600,35 +2524,11 @@ var Compile = (() => {
2600
2524
  }
2601
2525
  return void 0;
2602
2526
  }
2603
- parseDimensionWithX() {
2604
- if (this.current.type === "NUMBER_LITERAL") {
2605
- const dimensions = [];
2606
- const firstDim = parseInt(this.advance().value);
2607
- dimensions.push(
2608
- this.createNode("dimension", { size: firstDim })
2609
- );
2610
- if (this.current.type === "IDENTIFIER" && this.current.value.startsWith("x")) {
2611
- const dimString = this.current.value;
2612
- const matches = dimString.match(/x(\d+)/g);
2613
- if (matches && matches.join("") === dimString) {
2614
- this.advance();
2615
- for (const match of matches) {
2616
- const dimValue = parseInt(match.substring(1));
2617
- dimensions.push(
2618
- this.createNode("dimension", { size: dimValue })
2619
- );
2620
- }
2621
- } else if (dimString === "x" || dimString.startsWith("x")) {
2622
- this.error(
2623
- "Expected a positive integer literal or `?` after x. For example: `2x3` or `2x?`"
2624
- );
2625
- }
2626
- }
2627
- if (dimensions.length > 1) {
2628
- return dimensions;
2629
- }
2630
- }
2631
- return void 0;
2527
+ parseCaretDimensions() {
2528
+ const paren = this.match("(");
2529
+ const dimensions = this.parseDimensions();
2530
+ if (paren) this.expect(")");
2531
+ return dimensions;
2632
2532
  }
2633
2533
  parseTupleType() {
2634
2534
  if (this.current.type === "IDENTIFIER" && this.current.value === "tuple") {
@@ -2813,6 +2713,18 @@ var Compile = (() => {
2813
2713
  this.expect("..");
2814
2714
  const upperBound = this.parseValue();
2815
2715
  this.expect(">");
2716
+ const lower = lowerBound?.value ?? -Infinity;
2717
+ const upper = upperBound?.value ?? Infinity;
2718
+ if (Number.isNaN(lower) || Number.isNaN(upper))
2719
+ this.error(
2720
+ "Invalid numeric type",
2721
+ "Lower and upper bounds must be valid numbers"
2722
+ );
2723
+ if (lower > upper)
2724
+ this.error(
2725
+ `Invalid range: ${lower}..${upper}`,
2726
+ "The lower bound must be less than the upper bound"
2727
+ );
2816
2728
  return this.createNode("numeric", {
2817
2729
  baseType,
2818
2730
  lowerBound,
@@ -2827,7 +2739,7 @@ var Compile = (() => {
2827
2739
  parsePrimitiveType() {
2828
2740
  if (this.current.type === "IDENTIFIER") {
2829
2741
  const name = this.current.value;
2830
- if (PRIMITIVE_TYPES.includes(name)) {
2742
+ if (PRIMITIVE_TYPES_SET.has(name)) {
2831
2743
  this.advance();
2832
2744
  return this.createNode("primitive", { name });
2833
2745
  }
@@ -3161,14 +3073,32 @@ var Compile = (() => {
3161
3073
  }
3162
3074
 
3163
3075
  // src/common/type/parse.ts
3076
+ var TYPE_CACHE = /* @__PURE__ */ new Map();
3077
+ var TYPE_CACHE_MAX_SIZE = 2048;
3078
+ function deepFreeze(obj) {
3079
+ if (obj === null || typeof obj !== "object") return obj;
3080
+ if (Object.isFrozen(obj)) return obj;
3081
+ Object.freeze(obj);
3082
+ for (const value of Object.values(obj)) deepFreeze(value);
3083
+ return obj;
3084
+ }
3164
3085
  function parseType(s, typeResolver) {
3165
3086
  if (s === void 0) return void 0;
3166
3087
  if (isValidType(s)) return s;
3167
3088
  if (typeof s !== "string") return void 0;
3089
+ const cacheable = typeResolver === void 0;
3090
+ if (cacheable) {
3091
+ const cached = TYPE_CACHE.get(s);
3092
+ if (cached !== void 0) return cached;
3093
+ }
3168
3094
  try {
3169
3095
  const parser = new Parser(s, { typeResolver });
3170
3096
  const ast = parser.parseType();
3171
3097
  const type = buildTypeFromAST(ast, typeResolver);
3098
+ if (cacheable) {
3099
+ if (TYPE_CACHE.size >= TYPE_CACHE_MAX_SIZE) TYPE_CACHE.clear();
3100
+ TYPE_CACHE.set(s, deepFreeze(type));
3101
+ }
3172
3102
  return type;
3173
3103
  } catch (error) {
3174
3104
  throw new Error(
@@ -3243,19 +3173,54 @@ var Compile = (() => {
3243
3173
  color: [],
3244
3174
  expression: EXPRESSION_TYPES
3245
3175
  };
3176
+ var PRIMITIVE_SUBTYPES_CLOSURE = (() => {
3177
+ const closure = {};
3178
+ const closeOver = (t) => {
3179
+ if (closure[t]) return closure[t];
3180
+ const result = /* @__PURE__ */ new Set([t]);
3181
+ closure[t] = result;
3182
+ for (const sub2 of PRIMITIVE_SUBTYPES[t]) {
3183
+ if (sub2 === t) continue;
3184
+ for (const s of closeOver(sub2)) result.add(s);
3185
+ }
3186
+ return result;
3187
+ };
3188
+ for (const t of Object.keys(PRIMITIVE_SUBTYPES))
3189
+ closeOver(t);
3190
+ return closure;
3191
+ })();
3246
3192
  function isPrimitiveSubtype(lhs, rhs) {
3247
3193
  if (rhs === "any") return true;
3248
3194
  if (lhs === "never") return true;
3249
3195
  if (lhs === "unknown" || rhs === "unknown") return false;
3250
3196
  if (lhs === rhs) return true;
3251
- return PRIMITIVE_SUBTYPES[rhs].includes(lhs);
3197
+ return PRIMITIVE_SUBTYPES_CLOSURE[rhs].has(lhs);
3198
+ }
3199
+ function meetPrimitiveTypes(a, b) {
3200
+ if (a === b) return [a];
3201
+ const sa = PRIMITIVE_SUBTYPES_CLOSURE[a];
3202
+ const sb = PRIMITIVE_SUBTYPES_CLOSURE[b];
3203
+ if (sa.has(b)) return [b];
3204
+ if (sb.has(a)) return [a];
3205
+ const key = a < b ? `${a}|${b}` : `${b}|${a}`;
3206
+ const cached = MEET_CACHE.get(key);
3207
+ if (cached) return cached;
3208
+ const common = [];
3209
+ for (const t of sa) if (sb.has(t)) common.push(t);
3210
+ const maximals = common.filter(
3211
+ (t) => !common.some((u) => u !== t && PRIMITIVE_SUBTYPES_CLOSURE[u].has(t))
3212
+ );
3213
+ MEET_CACHE.set(key, maximals);
3214
+ return maximals;
3252
3215
  }
3216
+ var MEET_CACHE = /* @__PURE__ */ new Map();
3253
3217
  function isSubtype(lhs, rhs) {
3254
- if (typeof lhs === "string" && !PRIMITIVE_TYPES.includes(lhs))
3218
+ if (typeof lhs === "string" && !PRIMITIVE_TYPES_SET.has(lhs))
3255
3219
  lhs = parseType(lhs);
3256
- if (typeof rhs === "string" && !PRIMITIVE_TYPES.includes(rhs))
3220
+ if (typeof rhs === "string" && !PRIMITIVE_TYPES_SET.has(rhs))
3257
3221
  rhs = parseType(rhs);
3258
3222
  if (rhs === "any") return true;
3223
+ if (lhs === "never") return true;
3259
3224
  if (rhs === "never") return false;
3260
3225
  if (rhs === "error") return lhs === "error";
3261
3226
  if (rhs === "nothing") return lhs === "nothing";
@@ -3270,7 +3235,7 @@ var Compile = (() => {
3270
3235
  if (typeof lhs.value === "number") {
3271
3236
  if (Number.isInteger(lhs.value))
3272
3237
  return isPrimitiveSubtype("integer", rhs);
3273
- return isPrimitiveSubtype("number", rhs);
3238
+ return isPrimitiveSubtype("real", rhs);
3274
3239
  }
3275
3240
  if (typeof lhs.value === "boolean")
3276
3241
  return isPrimitiveSubtype("boolean", rhs);
@@ -3500,7 +3465,7 @@ var Compile = (() => {
3500
3465
  }
3501
3466
  function isNumeric(type) {
3502
3467
  if (typeof type === "string")
3503
- return NUMERIC_TYPES.includes(type);
3468
+ return NUMERIC_TYPES_SET.has(type);
3504
3469
  if (type.kind === "value") return typeof type.value === "number";
3505
3470
  if (type.kind === "numeric") return true;
3506
3471
  return false;
@@ -3508,7 +3473,7 @@ var Compile = (() => {
3508
3473
  function isScalar(type) {
3509
3474
  if (isNumeric(type)) return true;
3510
3475
  if (typeof type === "string")
3511
- return SCALAR_TYPES.includes(type);
3476
+ return SCALAR_TYPES_SET.has(type);
3512
3477
  if (type.kind === "value")
3513
3478
  return ["string", "boolean", "number"].includes(typeof type.value);
3514
3479
  return false;
@@ -3516,7 +3481,7 @@ var Compile = (() => {
3516
3481
  function isCollection(type) {
3517
3482
  if (isIndexedCollection(type)) return true;
3518
3483
  if (typeof type === "string")
3519
- return COLLECTION_TYPES.includes(type);
3484
+ return COLLECTION_TYPES_SET.has(type);
3520
3485
  return ["collection", "set", "record", "dictionary"].includes(type.kind);
3521
3486
  }
3522
3487
  function isIndexedCollection(type) {
@@ -3555,7 +3520,7 @@ var Compile = (() => {
3555
3520
  if (b === "unknown") return a;
3556
3521
  if (isSubtype(a, b)) return a;
3557
3522
  if (isSubtype(b, a)) return b;
3558
- return superType(a, b);
3523
+ return "never";
3559
3524
  }
3560
3525
  function widen2(a, b) {
3561
3526
  if (a === b) return a;
@@ -3568,7 +3533,43 @@ var Compile = (() => {
3568
3533
  if (b === "nothing") return a;
3569
3534
  if (isSubtype(a, b)) return b;
3570
3535
  if (isSubtype(b, a)) return a;
3571
- return superType(a, b);
3536
+ const sup = superType(a, b);
3537
+ if (LOSSY_SUPERTYPE.has(sup)) return unionTypes(a, b);
3538
+ return sup;
3539
+ }
3540
+ var LOSSY_SUPERTYPE = /* @__PURE__ */ new Set([
3541
+ "scalar",
3542
+ "value",
3543
+ "function",
3544
+ "expression",
3545
+ "collection",
3546
+ "indexed_collection",
3547
+ "list",
3548
+ "set",
3549
+ "tuple",
3550
+ "record",
3551
+ "dictionary",
3552
+ "map",
3553
+ "any"
3554
+ ]);
3555
+ function unionTypes(a, b) {
3556
+ const members = [];
3557
+ const keys = /* @__PURE__ */ new Set();
3558
+ const push = (t) => {
3559
+ if (typeof t === "object" && t.kind === "union") {
3560
+ for (const m of t.types) push(m);
3561
+ return;
3562
+ }
3563
+ const key = typeof t === "string" ? t : JSON.stringify(t);
3564
+ if (!keys.has(key)) {
3565
+ keys.add(key);
3566
+ members.push(t);
3567
+ }
3568
+ };
3569
+ push(a);
3570
+ push(b);
3571
+ if (members.length === 1) return members[0];
3572
+ return { kind: "union", types: members };
3572
3573
  }
3573
3574
  function narrow(...types) {
3574
3575
  if (types.length === 0) return "nothing";
@@ -3580,6 +3581,32 @@ var Compile = (() => {
3580
3581
  if (types.length === 1) return types[0];
3581
3582
  return types.reduce((a, b) => widen2(a, b));
3582
3583
  }
3584
+ var SUPERTYPE_PROBE_ORDER = [
3585
+ "non_finite_number",
3586
+ "finite_integer",
3587
+ "integer",
3588
+ "finite_rational",
3589
+ "rational",
3590
+ "finite_real",
3591
+ "real",
3592
+ "imaginary",
3593
+ "finite_complex",
3594
+ "complex",
3595
+ "finite_number",
3596
+ "number",
3597
+ "list",
3598
+ "record",
3599
+ "dictionary",
3600
+ "set",
3601
+ "tuple",
3602
+ "indexed_collection",
3603
+ "collection",
3604
+ "scalar",
3605
+ "value",
3606
+ "function",
3607
+ "expression"
3608
+ ];
3609
+ var PRIMITIVE_SUPERTYPE_CACHE = /* @__PURE__ */ new Map();
3583
3610
  function superType(a, b) {
3584
3611
  if (a === b) return a;
3585
3612
  if (a === "any" || b === "any") return "any";
@@ -3589,34 +3616,185 @@ var Compile = (() => {
3589
3616
  if (b === "unknown") return a;
3590
3617
  if (a === "nothing") return b;
3591
3618
  if (b === "nothing") return a;
3592
- if (commonSupertype(a, b, "non_finite_number")) return "non_finite_number";
3593
- if (commonSupertype(a, b, "finite_integer")) return "finite_integer";
3594
- if (commonSupertype(a, b, "integer")) return "integer";
3595
- if (commonSupertype(a, b, "finite_rational")) return "finite_rational";
3596
- if (commonSupertype(a, b, "rational")) return "rational";
3597
- if (commonSupertype(a, b, "finite_real")) return "finite_real";
3598
- if (commonSupertype(a, b, "real")) return "real";
3599
- if (commonSupertype(a, b, "imaginary")) return "imaginary";
3600
- if (commonSupertype(a, b, "finite_complex")) return "finite_complex";
3601
- if (commonSupertype(a, b, "complex")) return "complex";
3602
- if (commonSupertype(a, b, "finite_number")) return "finite_number";
3603
- if (commonSupertype(a, b, "number")) return "number";
3604
- if (commonSupertype(a, b, "list")) return "list";
3605
- if (commonSupertype(a, b, "record")) return "record";
3606
- if (commonSupertype(a, b, "dictionary")) return "dictionary";
3607
- if (commonSupertype(a, b, "set")) return "set";
3608
- if (commonSupertype(a, b, "tuple")) return "tuple";
3609
- if (commonSupertype(a, b, "indexed_collection")) return "indexed_collection";
3610
- if (commonSupertype(a, b, "collection")) return "collection";
3611
- if (commonSupertype(a, b, "scalar")) return "scalar";
3612
- if (commonSupertype(a, b, "value")) return "value";
3613
- if (commonSupertype(a, b, "function")) return "function";
3614
- if (commonSupertype(a, b, "expression")) return "expression";
3619
+ if (typeof a === "string" && typeof b === "string") {
3620
+ const key = a < b ? `${a}|${b}` : `${b}|${a}`;
3621
+ let result = PRIMITIVE_SUPERTYPE_CACHE.get(key);
3622
+ if (result === void 0) {
3623
+ result = "any";
3624
+ for (const ancestor of SUPERTYPE_PROBE_ORDER) {
3625
+ const subtypes = PRIMITIVE_SUBTYPES_CLOSURE[ancestor];
3626
+ if (subtypes.has(a) && subtypes.has(b)) {
3627
+ result = ancestor;
3628
+ break;
3629
+ }
3630
+ }
3631
+ PRIMITIVE_SUPERTYPE_CACHE.set(key, result);
3632
+ }
3633
+ return result;
3634
+ }
3635
+ for (const ancestor of SUPERTYPE_PROBE_ORDER)
3636
+ if (isSubtype(a, ancestor) && isSubtype(b, ancestor)) return ancestor;
3615
3637
  return "any";
3616
3638
  }
3617
- function commonSupertype(a, b, ancestor) {
3618
- if (isSubtype(a, ancestor) && isSubtype(b, ancestor)) return true;
3619
- return false;
3639
+
3640
+ // src/common/type/serialize.ts
3641
+ var NEGATION_PRECEDENCE = 3;
3642
+ var UNION_PRECEDENCE = 1;
3643
+ var INTERSECTION_PRECEDENCE = 2;
3644
+ var LIST_PRECEDENCE = 4;
3645
+ var RECORD_PRECEDENCE = 5;
3646
+ var DICTIONARY_PRECEDENCE = 6;
3647
+ var SET_PRECEDENCE = 7;
3648
+ var COLLECTION_PRECEDENCE = 8;
3649
+ var TUPLE_PRECEDENCE = 9;
3650
+ var SIGNATURE_PRECEDENCE = 10;
3651
+ var VALUE_PRECEDENCE = 11;
3652
+ function typeToString(type, precedence = 0) {
3653
+ if (typeof type === "string") return type;
3654
+ let result = "";
3655
+ switch (type.kind) {
3656
+ case "value":
3657
+ if (typeof type.value === "string") result = `"${type.value}"`;
3658
+ else if (typeof type.value === "boolean")
3659
+ result = type.value ? "true" : "false";
3660
+ else result = type.value.toString();
3661
+ break;
3662
+ case "reference":
3663
+ result = type.name;
3664
+ break;
3665
+ case "negation":
3666
+ result = `!${typeToString(type.type, NEGATION_PRECEDENCE)}`;
3667
+ break;
3668
+ case "union":
3669
+ result = type.types.map((t) => typeToString(t, UNION_PRECEDENCE)).join(" | ");
3670
+ break;
3671
+ case "intersection":
3672
+ result = type.types.map((t) => typeToString(t, INTERSECTION_PRECEDENCE)).join(" & ");
3673
+ break;
3674
+ case "expression":
3675
+ result = `expression<${symbolName(type.operator)}>`;
3676
+ break;
3677
+ case "symbol":
3678
+ result = `symbol<${symbolName(type.name)}>`;
3679
+ break;
3680
+ case "numeric":
3681
+ if (Number.isFinite(type.lower) && Number.isFinite(type.upper)) {
3682
+ result = `${type.type}<${type.lower}..${type.upper}>`;
3683
+ } else if (Number.isFinite(type.lower)) {
3684
+ result = `${type.type}<${type.lower}..>`;
3685
+ } else if (Number.isFinite(type.upper)) {
3686
+ result = `${type.type}<..${type.upper}>`;
3687
+ } else {
3688
+ result = `${type.type}`;
3689
+ }
3690
+ break;
3691
+ case "list":
3692
+ if (type.dimensions && typeof type.elements === "string" && NUMERIC_TYPES_SET.has(type.elements)) {
3693
+ if (type.dimensions === void 0) {
3694
+ if (type.elements === "number") result = "tensor";
3695
+ } else if (type.dimensions.length === 1) {
3696
+ if (type.elements === "number") {
3697
+ if (type.dimensions[0] < 0) result = "vector";
3698
+ else result = `vector<${type.dimensions[0]}>`;
3699
+ } else {
3700
+ if (type.dimensions[0] < 0)
3701
+ result = `vector<${typeToString(type.elements)}>`;
3702
+ else
3703
+ result = `vector<${typeToString(type.elements)}^${type.dimensions[0]}>`;
3704
+ }
3705
+ } else if (type.dimensions.length === 2) {
3706
+ const dims = type.dimensions;
3707
+ if (type.elements === "number") {
3708
+ if (dims[0] < 0 && dims[1] < 0) result = "matrix";
3709
+ else result = `matrix<${dims[0]}x${dims[1]}>`;
3710
+ } else {
3711
+ if (dims[0] < 0 && dims[1] < 0)
3712
+ result = `matrix<${typeToString(type.elements)}>`;
3713
+ else
3714
+ result = `matrix<${typeToString(type.elements)}^(${dims[0]}x${dims[1]})>`;
3715
+ }
3716
+ }
3717
+ }
3718
+ if (!result) {
3719
+ const dimensions = type.dimensions ? type.dimensions.length === 1 ? `^${type.dimensions[0].toString()}` : `^(${type.dimensions.join("x")})` : "";
3720
+ result = `list<${typeToString(type.elements)}${dimensions}>`;
3721
+ }
3722
+ break;
3723
+ case "record":
3724
+ const elements = Object.entries(type.elements).map(([key, value]) => `${key}: ${typeToString(value)}`).join(", ");
3725
+ result = `record<${elements}>`;
3726
+ break;
3727
+ case "dictionary":
3728
+ result = `dictionary<${typeToString(type.values)}>`;
3729
+ break;
3730
+ case "set":
3731
+ result = `set<${typeToString(type.elements)}>`;
3732
+ break;
3733
+ case "collection":
3734
+ result = `collection<${typeToString(type.elements)}>`;
3735
+ break;
3736
+ case "indexed_collection":
3737
+ result = `indexed_collection<${typeToString(type.elements)}>`;
3738
+ break;
3739
+ case "tuple":
3740
+ if (type.elements.length === 0) result = "tuple";
3741
+ else if (type.elements.length === 1) {
3742
+ const [el] = type.elements;
3743
+ result = `tuple<${namedElement(el)}>`;
3744
+ } else {
3745
+ result = "tuple<" + type.elements.map((el) => namedElement(el)).join(", ") + ">";
3746
+ }
3747
+ break;
3748
+ case "signature":
3749
+ const args = type.args ? type.args.map((arg) => namedElement(arg)).join(", ") : "";
3750
+ const optArgs = type.optArgs ? type.optArgs.map((arg) => namedElement(arg) + "?").join(", ") : "";
3751
+ const varArg = type.variadicArg ? type.variadicMin === 0 ? `${namedElement(type.variadicArg)}*` : `${namedElement(type.variadicArg)}+` : "";
3752
+ const argsList = [args, optArgs, varArg].filter((s) => s).join(", ");
3753
+ result = `(${argsList}) -> ${typeToString(type.result)}`;
3754
+ break;
3755
+ default:
3756
+ result = "error";
3757
+ }
3758
+ if (precedence > 0 && precedence > getPrecedence(type.kind))
3759
+ return `(${result})`;
3760
+ return result;
3761
+ }
3762
+ function namedElement(el) {
3763
+ if (el.name) return `${el.name}: ${typeToString(el.type)}`;
3764
+ return typeToString(el.type);
3765
+ }
3766
+ function symbolName(name) {
3767
+ if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) return name;
3768
+ return `\`${name}\``;
3769
+ }
3770
+ function getPrecedence(kind) {
3771
+ switch (kind) {
3772
+ case "negation":
3773
+ return NEGATION_PRECEDENCE;
3774
+ case "union":
3775
+ return UNION_PRECEDENCE;
3776
+ case "intersection":
3777
+ return INTERSECTION_PRECEDENCE;
3778
+ case "list":
3779
+ return LIST_PRECEDENCE;
3780
+ case "record":
3781
+ return RECORD_PRECEDENCE;
3782
+ case "dictionary":
3783
+ return DICTIONARY_PRECEDENCE;
3784
+ case "set":
3785
+ return SET_PRECEDENCE;
3786
+ case "collection":
3787
+ case "indexed_collection":
3788
+ return COLLECTION_PRECEDENCE;
3789
+ case "tuple":
3790
+ return TUPLE_PRECEDENCE;
3791
+ case "signature":
3792
+ return SIGNATURE_PRECEDENCE;
3793
+ case "value":
3794
+ return VALUE_PRECEDENCE;
3795
+ default:
3796
+ return 0;
3797
+ }
3620
3798
  }
3621
3799
 
3622
3800
  // src/common/type/utils.ts
@@ -3642,7 +3820,7 @@ var Compile = (() => {
3642
3820
  if (type.kind === "set") return type.elements;
3643
3821
  if (type.kind === "tuple") return widen(...type.elements.map((x) => x.type));
3644
3822
  if (type.kind === "dictionary")
3645
- return parseType(`tuple<string, ${type.values}>`);
3823
+ return parseType(`tuple<string, ${typeToString(type.values)}>`);
3646
3824
  if (type.kind === "record") {
3647
3825
  return parseType(
3648
3826
  `tuple<string, ${typeToString(widen(...Object.values(type.elements)))}>`
@@ -3725,6 +3903,12 @@ var Compile = (() => {
3725
3903
  return expr?._kind === "symbol" ? expr.symbol : void 0;
3726
3904
  }
3727
3905
 
3906
+ // src/compute-engine/boxed-expression/constraint-subject.ts
3907
+ var EMPTY_FACT_INDEX = Object.freeze({
3908
+ bySubject: /* @__PURE__ */ new Map(),
3909
+ membership: /* @__PURE__ */ new Map()
3910
+ });
3911
+
3728
3912
  // src/compute-engine/boxed-expression/stochastic-equal.ts
3729
3913
  var WELL_KNOWN_POINTS = [
3730
3914
  0,
@@ -3973,6 +4157,7 @@ var Compile = (() => {
3973
4157
  }
3974
4158
 
3975
4159
  // src/compute-engine/collection-utils.ts
4160
+ var MAX_SIZE_EAGER_COLLECTION = 100;
3976
4161
  function isFiniteIndexedCollection(col) {
3977
4162
  return (col.isFiniteCollection ?? false) && col.isIndexedCollection;
3978
4163
  }
@@ -4601,12 +4786,14 @@ var Compile = (() => {
4601
4786
  if (expr === null) return null;
4602
4787
  if (isDictionaryObject(expr)) return expr;
4603
4788
  const kv = keyValuePair(expr);
4604
- if (kv) return { [kv[0]]: kv[1] };
4789
+ if (kv)
4790
+ return {
4791
+ dict: { [kv[0]]: expressionToDictionaryValue(kv[1]) ?? "Nothing" }
4792
+ };
4605
4793
  if (operator(expr) === "Dictionary") {
4606
4794
  const dict = {};
4607
- const ops = operands(expr);
4608
- for (let i = 1; i < nops(expr); i++) {
4609
- const kv2 = keyValuePair(ops[i]);
4795
+ for (const op of operands(expr)) {
4796
+ const kv2 = keyValuePair(op);
4610
4797
  if (kv2) {
4611
4798
  dict[kv2[0]] = expressionToDictionaryValue(kv2[1]) ?? "Nothing";
4612
4799
  }
@@ -5544,15 +5731,16 @@ var Compile = (() => {
5544
5731
  precedence: ASSIGNMENT_PRECEDENCE,
5545
5732
  parse: parseAssign
5546
5733
  },
5547
- // General colon operator (type annotation, mapping notation)
5548
- // Precedence below assignment (260) so `:=` takes priority,
5549
- // and below arrows (270) so `f: A \to B` parses as `Colon(f, To(A, B))`
5734
+ // General colon operator (type annotation, mapping notation, Desmos piecewise)
5735
+ // Precedence below comparisons (245) so `cond : val` (Desmos compact piecewise)
5736
+ // parses as `Colon(cond, val)`, and below arrows (270) so
5737
+ // `f: A \to B` parses as `Colon(f, To(A, B))`.
5550
5738
  {
5551
5739
  name: "Colon",
5552
5740
  latexTrigger: ":",
5553
5741
  kind: "infix",
5554
5742
  associativity: "right",
5555
- precedence: 250,
5743
+ precedence: 240,
5556
5744
  serialize: (serializer, expr) => joinLatex([
5557
5745
  serializer.serialize(operand(expr, 1)),
5558
5746
  "\\colon",
@@ -5563,7 +5751,7 @@ var Compile = (() => {
5563
5751
  latexTrigger: "\\colon",
5564
5752
  kind: "infix",
5565
5753
  associativity: "right",
5566
- precedence: 250,
5754
+ precedence: 240,
5567
5755
  parse: "Colon"
5568
5756
  },
5569
5757
  {
@@ -6539,6 +6727,7 @@ var Compile = (() => {
6539
6727
  }
6540
6728
  }
6541
6729
  if (!variable) return null;
6730
+ if (symbol(variable) === null) return null;
6542
6731
  parser.skipSpace();
6543
6732
  const fn = parser.parseExpression({ minPrec: 740 });
6544
6733
  if (!fn) return null;
@@ -6725,7 +6914,7 @@ var Compile = (() => {
6725
6914
  if (runs.length === 1) body = runs[0];
6726
6915
  else {
6727
6916
  if (runs.every((x) => stringValue(x) !== null))
6728
- body = "'" + runs.map((x) => stringValue(x)).join() + "'";
6917
+ body = "'" + runs.map((x) => stringValue(x)).join("") + "'";
6729
6918
  else body = ["Text", ...runs];
6730
6919
  }
6731
6920
  return style ? ["Annotated", body, dictionaryFromEntries(style)] : body;
@@ -7133,7 +7322,10 @@ var Compile = (() => {
7133
7322
  p.skipVisualSpace();
7134
7323
  const isComma = p.peek === ",";
7135
7324
  p.index = saved;
7136
- return isComma;
7325
+ if (isComma) return true;
7326
+ if (peekKeyword(p, "where")) return true;
7327
+ if (peekKeyword(p, "with")) return true;
7328
+ return false;
7137
7329
  }
7138
7330
  };
7139
7331
  const elements = [];
@@ -7174,6 +7366,25 @@ var Compile = (() => {
7174
7366
  parser.skipVisualSpace();
7175
7367
  } while (parser.match(","));
7176
7368
  if (bindings.length === 0) return null;
7369
+ const forStart = parser.index;
7370
+ if (matchKeyword(parser, "for")) {
7371
+ const loop = parseForComprehension(parser, lhs, until);
7372
+ if (loop) {
7373
+ const block2 = [];
7374
+ for (const b of bindings) {
7375
+ const normalized = normalizeLocalAssign(b);
7376
+ if (operator(normalized) === "Assign") {
7377
+ block2.push(["Declare", operand(normalized, 1)]);
7378
+ block2.push(normalized);
7379
+ } else {
7380
+ block2.push(normalized);
7381
+ }
7382
+ }
7383
+ block2.push(loop);
7384
+ return ["Block", ...block2];
7385
+ }
7386
+ parser.index = forStart;
7387
+ }
7177
7388
  const block = [];
7178
7389
  for (const b of bindings) {
7179
7390
  const normalized = normalizeLocalAssign(b);
@@ -7387,6 +7598,17 @@ var Compile = (() => {
7387
7598
  const upperExpr = openRight ? ["Open", upper] : upper;
7388
7599
  return ["Interval", lowerExpr, upperExpr];
7389
7600
  }
7601
+ var COMPARISON_HEADS = /* @__PURE__ */ new Set([
7602
+ "Less",
7603
+ "LessEqual",
7604
+ "Greater",
7605
+ "GreaterEqual",
7606
+ "Equal",
7607
+ "NotEqual",
7608
+ "And",
7609
+ "Or",
7610
+ "Not"
7611
+ ]);
7390
7612
  var DEFINITIONS_SETS = [
7391
7613
  //
7392
7614
  // Constants
@@ -7645,18 +7867,58 @@ var Compile = (() => {
7645
7867
  closeTrigger: "}",
7646
7868
  parse: (_parser, body) => {
7647
7869
  if (isEmptySequence(body)) return "EmptySet";
7870
+ if (operator(body) == "Delimiter" && stringValue(operand(body, 2)) === ",") {
7871
+ body = operand(body, 1);
7872
+ }
7648
7873
  const h = operator(body);
7649
- if (h === "Divides" || h === "Colon") {
7874
+ if (h === "Divides") {
7650
7875
  const expr = operand(body, 1);
7651
7876
  const condition = operand(body, 2);
7652
7877
  if (expr !== null && condition !== null)
7653
7878
  return ["Set", expr, ["Condition", condition]];
7654
7879
  }
7655
- if (operator(body) == "Delimiter" && stringValue(operand(body, 2)) === ",") {
7656
- body = operand(body, 1);
7880
+ if (h === "Colon") {
7881
+ const lhs = operand(body, 1);
7882
+ const rhs = operand(body, 2);
7883
+ if (lhs !== null && rhs !== null) {
7884
+ const lhsOp = operator(lhs);
7885
+ if (lhsOp !== null && COMPARISON_HEADS.has(lhsOp)) {
7886
+ return ["Which", lhs, rhs];
7887
+ }
7888
+ return ["Set", lhs, ["Condition", rhs]];
7889
+ }
7890
+ }
7891
+ if (h === "Sequence") {
7892
+ const elements = operands(body);
7893
+ const colonElements = elements.filter((el) => operator(el) === "Colon");
7894
+ const allPiecewise = colonElements.length > 0 && colonElements.every((el) => {
7895
+ const lhs = operand(el, 1);
7896
+ const lhsOp = lhs !== null ? operator(lhs) : null;
7897
+ return lhsOp !== null && COMPARISON_HEADS.has(lhsOp);
7898
+ });
7899
+ if (allPiecewise) {
7900
+ const whichOps = [];
7901
+ for (let i = 0; i < elements.length; i++) {
7902
+ const el = elements[i];
7903
+ if (operator(el) === "Colon") {
7904
+ const cond = operand(el, 1);
7905
+ const val = operand(el, 2);
7906
+ if (cond === null || val === null) {
7907
+ return ["Set", ...elements];
7908
+ }
7909
+ whichOps.push(cond, val);
7910
+ } else {
7911
+ if (i !== elements.length - 1) {
7912
+ return ["Set", ...elements];
7913
+ }
7914
+ whichOps.push("True", el);
7915
+ }
7916
+ }
7917
+ return ["Which", ...whichOps];
7918
+ }
7919
+ return ["Set", ...elements];
7657
7920
  }
7658
- if (operator(body) !== "Sequence") return ["Set", body];
7659
- return ["Set", ...operands(body)];
7921
+ return ["Set", body];
7660
7922
  },
7661
7923
  serialize: (serializer, expr) => {
7662
7924
  if (nops(expr) === 2 && operator(operand(expr, 2)) === "Condition") {
@@ -8185,6 +8447,8 @@ var Compile = (() => {
8185
8447
  const h = operator(arg);
8186
8448
  if (prevWasNumber && (h === "Divide" || h === "Rational")) {
8187
8449
  result = latexTemplate(serializer.options.multiply, result, term);
8450
+ } else if (/^\d/.test(term)) {
8451
+ result = latexTemplate(serializer.options.multiply, result, term);
8188
8452
  } else if (!serializer.options.invisibleMultiply) {
8189
8453
  result = joinLatex([result, term]);
8190
8454
  } else {
@@ -9630,7 +9894,9 @@ var Compile = (() => {
9630
9894
  minPrec: MULTIPLICATION_PRECEDENCE,
9631
9895
  condition: (parser2) => trigCommands[parser2.peek] || (until?.condition?.(parser2) ?? false)
9632
9896
  });
9633
- const appliedFn = args === null ? fn : typeof fn === "string" ? [fn, ...args] : ["Apply", fn, ...args];
9897
+ const isTwoArgArctan = args?.length === 2 && (fn === "Arctan" || Array.isArray(fn) && fn[0] === "InverseFunction" && fn[1] === "Tan");
9898
+ const head = isTwoArgArctan ? "Arctan2" : fn;
9899
+ const appliedFn = args === null ? fn : typeof head === "string" ? [head, ...args] : ["Apply", head, ...args];
9634
9900
  return sup === null ? appliedFn : ["Power", appliedFn, sup];
9635
9901
  };
9636
9902
  }
@@ -11753,10 +12019,17 @@ var Compile = (() => {
11753
12019
  // The capitalized library entries already exist; these are pure parse
11754
12020
  // aliases so the lowercase names don't land in `unsupported-operator`.
11755
12021
  // ---------------------------------------------------------------------------
12022
+ { latexTrigger: "\\operatorname{count}", parse: "Length" },
11756
12023
  { latexTrigger: "\\operatorname{random}", parse: "Random" },
11757
12024
  { latexTrigger: "\\operatorname{shuffle}", parse: "Shuffle" },
11758
12025
  { latexTrigger: "\\operatorname{repeat}", parse: "Repeat" },
11759
12026
  { latexTrigger: "\\operatorname{join}", parse: "Join" },
12027
+ { latexTrigger: "\\operatorname{range}", parse: "Range" },
12028
+ // Note: `\operatorname{with}` (Desmos's local-binding clause) is intentionally
12029
+ // NOT registered here. Use the math-notation equivalent `\operatorname{where}`
12030
+ // (with `\coloneq` for bindings), or register `with` as a custom dictionary
12031
+ // entry at the integration layer — see the "Desmos-Specific Syntax — Prefer
12032
+ // Custom LaTeX Dictionary" section in COMPUTE_ENGINE.md for a worked example.
11760
12033
  // ---------------------------------------------------------------------------
11761
12034
  // Geometric primitive heads. Registered as known typed heads so consumers
11762
12035
  // can branch on the operator name; CE itself doesn't render them. The
@@ -11909,6 +12182,30 @@ var Compile = (() => {
11909
12182
  var SOME_EMOJI = new RegExp(`(?:${POSSIBLE_EMOJI})+`, "u");
11910
12183
  var EMOJIS = new RegExp(`^(?:${POSSIBLE_EMOJI})+$`, "u");
11911
12184
 
12185
+ // src/compute-engine/latex-syntax/parse.ts
12186
+ var PARSE_TOKEN_EXCLUDED = /* @__PURE__ */ new Set([
12187
+ ...'!"#$%&(),/;:?@[]\\`|~'.split(""),
12188
+ "\\left",
12189
+ "\\bigl",
12190
+ "\\mleft"
12191
+ ]);
12192
+ var TEX_UNIT_TOKENS = [
12193
+ "pt",
12194
+ "em",
12195
+ "mu",
12196
+ "ex",
12197
+ "mm",
12198
+ "cm",
12199
+ "in",
12200
+ "bp",
12201
+ "sp",
12202
+ "dd",
12203
+ "cc",
12204
+ "pc",
12205
+ "nc",
12206
+ "nd"
12207
+ ].map((unit) => [...unit]);
12208
+
11912
12209
  // src/compute-engine/boxed-expression/utils.ts
11913
12210
  function isValueDef(def) {
11914
12211
  return def !== void 0 && "value" in def;
@@ -11944,6 +12241,50 @@ var Compile = (() => {
11944
12241
  return ys;
11945
12242
  }
11946
12243
 
12244
+ // src/common/fuzzy-string-match.ts
12245
+ function levenshtein(source, target) {
12246
+ if (source === target) return 0;
12247
+ if (source.length === 0) return target.length;
12248
+ if (target.length === 0) return source.length;
12249
+ let prevRow = Array.from(
12250
+ { length: source.length + 1 },
12251
+ (_, j) => j
12252
+ );
12253
+ let currRow = new Array(source.length + 1);
12254
+ for (let i = 1; i <= target.length; i++) {
12255
+ currRow[0] = i;
12256
+ for (let j = 1; j <= source.length; j++) {
12257
+ const cost = source[j - 1] === target[i - 1] ? 0 : 1;
12258
+ currRow[j] = Math.min(
12259
+ prevRow[j] + 1,
12260
+ // deletion
12261
+ currRow[j - 1] + 1,
12262
+ // insertion
12263
+ prevRow[j - 1] + cost
12264
+ // substitution
12265
+ );
12266
+ }
12267
+ [prevRow, currRow] = [currRow, prevRow];
12268
+ }
12269
+ return prevRow[source.length];
12270
+ }
12271
+ function fuzzyStringMatch(invalidWord, validWords) {
12272
+ const threshold = 7;
12273
+ let bestMatch = null;
12274
+ let minDistance = Infinity;
12275
+ const invalidLength = invalidWord.length;
12276
+ for (const word of validWords) {
12277
+ if (Math.abs(invalidLength - word.length) > threshold) continue;
12278
+ const distance = levenshtein(invalidWord, word);
12279
+ if (distance === 0) return word;
12280
+ if (distance <= threshold && distance < minDistance) {
12281
+ minDistance = distance;
12282
+ bestMatch = word;
12283
+ }
12284
+ }
12285
+ return bestMatch;
12286
+ }
12287
+
11947
12288
  // src/compute-engine/boxed-expression/validate.ts
11948
12289
  function checkArity(ce, ops, count) {
11949
12290
  ops = flatten(ops);
@@ -12886,12 +13227,240 @@ ${lines.join("\n")}`;
12886
13227
  Complex["EPSILON"] = 1e-15;
12887
13228
 
12888
13229
  // src/compute-engine/boxed-expression/numerics.ts
13230
+ function asSmallInteger(expr) {
13231
+ if (expr === void 0 || expr === null) return null;
13232
+ if (typeof expr === "number") {
13233
+ if (Number.isInteger(expr) && expr >= -SMALL_INTEGER && expr <= SMALL_INTEGER)
13234
+ return expr;
13235
+ return null;
13236
+ }
13237
+ if (!isNumber(expr)) return null;
13238
+ const num = expr.numericValue;
13239
+ if (typeof num === "number") {
13240
+ if (Number.isInteger(num) && num >= -SMALL_INTEGER && num <= SMALL_INTEGER)
13241
+ return num;
13242
+ return null;
13243
+ }
13244
+ if (num.im !== 0) return null;
13245
+ const n = num.re;
13246
+ if (Number.isInteger(n) && n >= -SMALL_INTEGER && n <= SMALL_INTEGER)
13247
+ return Number(n);
13248
+ return null;
13249
+ }
12889
13250
  function toInteger(expr) {
12890
13251
  if (!isNumber(expr)) return null;
12891
13252
  const num = expr.numericValue;
12892
13253
  return Math.round(typeof num === "number" ? num : num.re);
12893
13254
  }
12894
13255
 
13256
+ // src/compute-engine/library/logic-analysis.ts
13257
+ function filterValuesWithCondition(values, variable, conditionExpr, _ce) {
13258
+ return values.filter((value) => {
13259
+ const substituted = conditionExpr.subs({ [variable]: value });
13260
+ const result = substituted.evaluate();
13261
+ return sym(result) === "True";
13262
+ });
13263
+ }
13264
+ function extractFiniteDomainWithReason(condition, ce) {
13265
+ if (condition.operator !== "Element") {
13266
+ return { status: "error", reason: "expected-element-expression" };
13267
+ }
13268
+ if (!isFunction2(condition)) {
13269
+ return { status: "error", reason: "expected-element-expression" };
13270
+ }
13271
+ const variable = isSymbol2(condition.op1) ? condition.op1.symbol : void 0;
13272
+ if (!variable) {
13273
+ return { status: "error", reason: "expected-index-variable" };
13274
+ }
13275
+ const domain = condition.op2;
13276
+ if (!domain) {
13277
+ return { status: "error", reason: "expected-domain" };
13278
+ }
13279
+ const maybeCondition = condition.op3;
13280
+ const filterCondition = condition.nops >= 3 && maybeCondition && sym(maybeCondition) !== "Nothing" ? maybeCondition : null;
13281
+ const successResult = (values) => {
13282
+ if (filterCondition) {
13283
+ const filteredValues = filterValuesWithCondition(
13284
+ values,
13285
+ variable,
13286
+ filterCondition,
13287
+ ce
13288
+ );
13289
+ return { status: "success", variable, values: filteredValues };
13290
+ }
13291
+ return { status: "success", variable, values };
13292
+ };
13293
+ if (domain.operator === "Set" || domain.operator === "List") {
13294
+ const values = isFunction2(domain) ? domain.ops : void 0;
13295
+ if (values && values.length <= 1e3) {
13296
+ if (domain.operator === "List" && values.length === 2) {
13297
+ const start = asSmallInteger(values[0]);
13298
+ const end = asSmallInteger(values[1]);
13299
+ if (start !== null && end !== null) {
13300
+ const count = end - start + 1;
13301
+ if (count > 0 && count <= 1e3) {
13302
+ const rangeValues = [];
13303
+ for (let i = start; i <= end; i++) {
13304
+ rangeValues.push(ce.number(i));
13305
+ }
13306
+ return successResult(rangeValues);
13307
+ }
13308
+ if (count > 1e3) {
13309
+ return {
13310
+ status: "non-enumerable",
13311
+ variable,
13312
+ domain,
13313
+ reason: "domain-too-large"
13314
+ };
13315
+ }
13316
+ }
13317
+ }
13318
+ return successResult([...values]);
13319
+ }
13320
+ if (values && values.length > 1e3) {
13321
+ return {
13322
+ status: "non-enumerable",
13323
+ variable,
13324
+ domain,
13325
+ reason: "domain-too-large"
13326
+ };
13327
+ }
13328
+ return { status: "error", reason: "empty-domain" };
13329
+ }
13330
+ if (isFunction2(domain, "Range")) {
13331
+ const start = asSmallInteger(domain.op1);
13332
+ const end = asSmallInteger(domain.op2);
13333
+ const step = domain.ops.length >= 3 ? asSmallInteger(domain.op3) : 1;
13334
+ if (start !== null && end !== null && step !== null && step !== 0) {
13335
+ const count = Math.floor((end - start) / step) + 1;
13336
+ if (count > 0 && count <= 1e3) {
13337
+ const values = [];
13338
+ for (let i = start; step > 0 ? i <= end : i >= end; i += step) {
13339
+ values.push(ce.number(i));
13340
+ }
13341
+ return successResult(values);
13342
+ }
13343
+ if (count > 1e3) {
13344
+ return {
13345
+ status: "non-enumerable",
13346
+ variable,
13347
+ domain,
13348
+ reason: "domain-too-large"
13349
+ };
13350
+ }
13351
+ }
13352
+ return {
13353
+ status: "non-enumerable",
13354
+ variable,
13355
+ domain,
13356
+ reason: "non-integer-bounds"
13357
+ };
13358
+ }
13359
+ if (isFunction2(domain, "Interval")) {
13360
+ let op1 = domain.op1;
13361
+ let op2 = domain.op2;
13362
+ let openStart = false;
13363
+ let openEnd = false;
13364
+ if (isFunction2(op1, "Open")) {
13365
+ openStart = true;
13366
+ op1 = op1.op1;
13367
+ } else if (isFunction2(op1, "Closed")) {
13368
+ op1 = op1.op1;
13369
+ }
13370
+ if (isFunction2(op2, "Open")) {
13371
+ openEnd = true;
13372
+ op2 = op2.op1;
13373
+ } else if (isFunction2(op2, "Closed")) {
13374
+ op2 = op2.op1;
13375
+ }
13376
+ let start = asSmallInteger(op1);
13377
+ let end = asSmallInteger(op2);
13378
+ if (start !== null && end !== null) {
13379
+ if (openStart) start += 1;
13380
+ if (openEnd) end -= 1;
13381
+ const count = end - start + 1;
13382
+ if (count > 0 && count <= 1e3) {
13383
+ const values = [];
13384
+ for (let i = start; i <= end; i++) {
13385
+ values.push(ce.number(i));
13386
+ }
13387
+ return successResult(values);
13388
+ }
13389
+ if (count > 1e3) {
13390
+ return {
13391
+ status: "non-enumerable",
13392
+ variable,
13393
+ domain,
13394
+ reason: "domain-too-large"
13395
+ };
13396
+ }
13397
+ }
13398
+ return {
13399
+ status: "non-enumerable",
13400
+ variable,
13401
+ domain,
13402
+ reason: "non-integer-bounds"
13403
+ };
13404
+ }
13405
+ const domainSymbol = sym(domain);
13406
+ if (domainSymbol) {
13407
+ const knownInfiniteSets = [
13408
+ "Integers",
13409
+ "NonNegativeIntegers",
13410
+ "PositiveIntegers",
13411
+ "NegativeIntegers",
13412
+ "Rationals",
13413
+ "Reals",
13414
+ "PositiveReals",
13415
+ "NonNegativeReals",
13416
+ "NegativeReals",
13417
+ "NonPositiveReals",
13418
+ "ExtendedReals",
13419
+ "Complexes",
13420
+ "ImaginaryNumbers",
13421
+ "Numbers",
13422
+ "ExtendedComplexes",
13423
+ "AlgebraicNumbers",
13424
+ "TranscendentalNumbers"
13425
+ ];
13426
+ if (knownInfiniteSets.includes(domainSymbol)) {
13427
+ return {
13428
+ status: "non-enumerable",
13429
+ variable,
13430
+ domain,
13431
+ reason: "infinite-domain"
13432
+ };
13433
+ }
13434
+ const domainValue = domain.value;
13435
+ if (domainValue && domainValue.operator === "Set" && isFunction2(domainValue)) {
13436
+ const values = domainValue.ops;
13437
+ if (values && values.length <= 1e3) {
13438
+ return successResult([...values]);
13439
+ }
13440
+ if (values && values.length > 1e3) {
13441
+ return {
13442
+ status: "non-enumerable",
13443
+ variable,
13444
+ domain,
13445
+ reason: "domain-too-large"
13446
+ };
13447
+ }
13448
+ }
13449
+ return {
13450
+ status: "non-enumerable",
13451
+ variable,
13452
+ domain,
13453
+ reason: "unknown-domain"
13454
+ };
13455
+ }
13456
+ return {
13457
+ status: "non-enumerable",
13458
+ variable,
13459
+ domain,
13460
+ reason: "unrecognized-domain-type"
13461
+ };
13462
+ }
13463
+
12895
13464
  // src/compute-engine/numerics/interval.ts
12896
13465
  function isNumber2(expr) {
12897
13466
  return expr?._kind === "number";
@@ -12946,6 +13515,20 @@ ${lines.join("\n")}`;
12946
13515
  }
12947
13516
  return void 0;
12948
13517
  }
13518
+ function intervalContains(int, val) {
13519
+ if (int.openStart ? val <= int.start : val < int.start) return false;
13520
+ if (int.openEnd ? val >= int.end : val > int.end) return false;
13521
+ return true;
13522
+ }
13523
+
13524
+ // src/compute-engine/numerics/random.ts
13525
+ function deterministicRandom(seed) {
13526
+ const v = Math.sin(seed * 12.9898) * 43758.5453;
13527
+ return v - Math.floor(v);
13528
+ }
13529
+ function nextSeed(seed) {
13530
+ return seed + 0.6180339887498949;
13531
+ }
12949
13532
 
12950
13533
  // src/compute-engine/boxed-expression/canonical-utils.ts
12951
13534
  function canonical(ce, xs, scope) {
@@ -12953,8 +13536,236 @@ ${lines.join("\n")}`;
12953
13536
  return xs.map((x) => ce.expr(x, { scope }));
12954
13537
  }
12955
13538
 
13539
+ // src/common/type/reduce.ts
13540
+ function reduceType(type) {
13541
+ if (typeof type === "string") {
13542
+ if (!isValidPrimitiveType(type)) return "error";
13543
+ return type;
13544
+ }
13545
+ switch (type.kind) {
13546
+ case "union":
13547
+ return reduceUnionType(type);
13548
+ case "intersection":
13549
+ return reduceIntersectionType(type);
13550
+ case "negation":
13551
+ return reduceNegationType(type);
13552
+ case "collection":
13553
+ case "indexed_collection":
13554
+ return reduceCollectionType(type.kind, type);
13555
+ case "list":
13556
+ return reduceListType(type);
13557
+ case "set":
13558
+ return reduceSetType(type);
13559
+ case "tuple":
13560
+ return reduceTupleType(type);
13561
+ case "record":
13562
+ return reduceRecordType(type);
13563
+ case "dictionary":
13564
+ return reduceDictionaryType(type);
13565
+ case "signature":
13566
+ return reduceSignatureType(type);
13567
+ case "value":
13568
+ return type;
13569
+ case "reference":
13570
+ return type;
13571
+ default:
13572
+ throw new Error(`Unknown type kind: ${type}`);
13573
+ }
13574
+ }
13575
+ function decorate(t) {
13576
+ if (typeof t !== "object") return t;
13577
+ if (Object.isFrozen(t) || Object.prototype.hasOwnProperty.call(t, "toString"))
13578
+ return t;
13579
+ Object.defineProperty(t, "toString", { value: () => typeToString(t) });
13580
+ return t;
13581
+ }
13582
+ function reduceMembers(types) {
13583
+ const result = [];
13584
+ const seen = /* @__PURE__ */ new Set();
13585
+ for (const t of types) {
13586
+ const reduced = reduceType(t);
13587
+ const key = typeof reduced === "string" ? reduced : typeToString(reduced);
13588
+ if (!seen.has(key)) {
13589
+ seen.add(key);
13590
+ result.push(reduced);
13591
+ }
13592
+ }
13593
+ return result;
13594
+ }
13595
+ function reduceNegationType(type) {
13596
+ const reducedType = reduceType(type.type);
13597
+ if (reducedType === "nothing") return "any";
13598
+ if (reducedType === "any") return "nothing";
13599
+ return decorate({ kind: "negation", type: reducedType });
13600
+ }
13601
+ function reduceUnionType(type) {
13602
+ const reducedTypes = reduceMembers(type.types);
13603
+ if (reducedTypes.length === 0) return "never";
13604
+ if (reducedTypes.some((type2) => type2 === "error")) return "error";
13605
+ if (reducedTypes.length === 1) return decorate(reducedTypes[0]);
13606
+ const acc = [];
13607
+ for (const current of reducedTypes) {
13608
+ if (acc.some((t) => isSubtype(current, t))) continue;
13609
+ for (let i = acc.length - 1; i >= 0; i--)
13610
+ if (isSubtype(acc[i], current)) acc.splice(i, 1);
13611
+ acc.push(current);
13612
+ }
13613
+ if (acc.length === 1) return decorate(acc[0]);
13614
+ return decorate({ kind: "union", types: acc });
13615
+ }
13616
+ function meet2(a, b) {
13617
+ if (isSubtype(a, b)) return a;
13618
+ if (isSubtype(b, a)) return b;
13619
+ if (typeof a === "object" && a.kind === "union") return meetUnion(a.types, b);
13620
+ if (typeof b === "object" && b.kind === "union") return meetUnion(b.types, a);
13621
+ if (typeof a === "string" && typeof b === "string") {
13622
+ const maximals = meetPrimitiveTypes(a, b);
13623
+ if (maximals.length === 0) return "nothing";
13624
+ if (maximals.length === 1) return maximals[0];
13625
+ return { kind: "union", types: maximals };
13626
+ }
13627
+ return "nothing";
13628
+ }
13629
+ function meetUnion(types, b) {
13630
+ const members = types.map((t) => meet2(t, b)).filter((t) => t !== "nothing");
13631
+ if (members.length === 0) return "nothing";
13632
+ if (members.length === 1) return members[0];
13633
+ return reduceUnionType({ kind: "union", types: members });
13634
+ }
13635
+ function reduceIntersectionType(type) {
13636
+ const reducedTypes = reduceMembers(type.types);
13637
+ if (reducedTypes.length === 0) return "nothing";
13638
+ if (reducedTypes.some((type2) => type2 === "error")) return "error";
13639
+ let result = reducedTypes[0];
13640
+ for (let i = 1; i < reducedTypes.length; i++) {
13641
+ result = meet2(result, reducedTypes[i]);
13642
+ if (result === "nothing") return "nothing";
13643
+ }
13644
+ return decorate(result);
13645
+ }
13646
+ function reduceCollectionType(kind, type) {
13647
+ const reducedType = reduceType(type.elements);
13648
+ if (reducedType === "error") return "error";
13649
+ if (reducedType === "nothing") return decorate({ kind, elements: "nothing" });
13650
+ if (reducedType === "any") return kind;
13651
+ return decorate({
13652
+ ...type,
13653
+ elements: reducedType
13654
+ });
13655
+ }
13656
+ function reduceListType(type) {
13657
+ const reducedType = reduceType(type.elements);
13658
+ if (reducedType === "error") return "error";
13659
+ if (reducedType === "nothing")
13660
+ return decorate({ kind: "list", elements: "nothing" });
13661
+ if (reducedType === "any") return "list";
13662
+ let dimensions = type.dimensions;
13663
+ if (dimensions) {
13664
+ dimensions = dimensions.filter((dim) => dim >= 1 || dim === -1);
13665
+ if (dimensions.length === 0) return "nothing";
13666
+ }
13667
+ return decorate({
13668
+ ...type,
13669
+ dimensions,
13670
+ elements: reducedType
13671
+ });
13672
+ }
13673
+ function reduceSetType(type) {
13674
+ const reducedType = reduceType(type.elements);
13675
+ if (reducedType === "error") return "error";
13676
+ if (reducedType === "nothing")
13677
+ return decorate({ kind: "set", elements: "nothing" });
13678
+ if (reducedType === "any") return "set";
13679
+ return decorate({
13680
+ ...type,
13681
+ elements: reducedType
13682
+ });
13683
+ }
13684
+ function reduceTupleType(type) {
13685
+ let reducedElements = type.elements.map((element) => ({
13686
+ ...element,
13687
+ type: reduceType(element.type)
13688
+ }));
13689
+ if (reducedElements.length === 0) return "nothing";
13690
+ if (reducedElements.some((element) => element.type === "error"))
13691
+ return "error";
13692
+ reducedElements = reducedElements.filter(
13693
+ (element) => element.type !== "nothing"
13694
+ );
13695
+ return decorate({
13696
+ ...type,
13697
+ elements: reducedElements
13698
+ });
13699
+ }
13700
+ function reduceRecordType(type) {
13701
+ let reducedElements = {};
13702
+ for (const [key, value] of Object.entries(type.elements))
13703
+ reducedElements[key] = reduceType(value);
13704
+ if (Object.values(reducedElements).some((type2) => type2 === "error"))
13705
+ return "error";
13706
+ reducedElements = Object.fromEntries(
13707
+ Object.entries(reducedElements).filter(([_, value]) => value !== "nothing")
13708
+ );
13709
+ if (Object.keys(reducedElements).length === 0) return "record";
13710
+ return decorate({
13711
+ ...type,
13712
+ elements: reducedElements
13713
+ });
13714
+ }
13715
+ function reduceDictionaryType(type) {
13716
+ const reducedValues = reduceType(type.values);
13717
+ if (reducedValues === "error") return "error";
13718
+ if (reducedValues === "nothing") return "error";
13719
+ if (reducedValues === "any" || reducedValues === "unknown") return "any";
13720
+ return decorate({ kind: "dictionary", values: reducedValues });
13721
+ }
13722
+ function reduceSignatureType(type) {
13723
+ const reducedArgs = type.args?.map((arg) => ({
13724
+ ...arg,
13725
+ type: reduceType(arg.type)
13726
+ }));
13727
+ let reducedOptArgs = type.optArgs?.map((arg) => ({
13728
+ ...arg,
13729
+ type: reduceType(arg.type)
13730
+ }));
13731
+ let reducedVarArg = type.variadicArg ? {
13732
+ ...type.variadicArg,
13733
+ type: reduceType(type.variadicArg.type)
13734
+ } : void 0;
13735
+ const reducedResult = reduceType(type.result);
13736
+ if (reducedArgs?.some((arg) => arg.type === "error")) return "error";
13737
+ if (reducedOptArgs?.some((arg) => arg.type === "error")) return "error";
13738
+ if (reducedVarArg?.type === "error") return "error";
13739
+ if (reducedResult === "error") return "error";
13740
+ reducedOptArgs = reducedOptArgs?.filter((arg) => arg.type !== "nothing");
13741
+ if (reducedArgs?.length === 0) reducedOptArgs = void 0;
13742
+ if (reducedOptArgs?.length === 0) reducedOptArgs = void 0;
13743
+ if (reducedVarArg?.type === "nothing") reducedVarArg = void 0;
13744
+ return decorate({
13745
+ ...type,
13746
+ args: reducedArgs,
13747
+ optArgs: reducedOptArgs,
13748
+ variadicArg: reducedVarArg,
13749
+ variadicMin: reducedVarArg ? type.variadicMin : void 0,
13750
+ result: reducedResult
13751
+ });
13752
+ }
13753
+
13754
+ // src/compute-engine/library/sets.ts
13755
+ function typeIntersection(a, b) {
13756
+ return reduceType({ kind: "intersection", types: [a, b] });
13757
+ }
13758
+ function typeMembership(x, t) {
13759
+ const vt = x.type;
13760
+ if (vt.matches(t)) return true;
13761
+ if (typeIntersection(vt.type, t) === "nothing") return false;
13762
+ if (isNumber(x)) return false;
13763
+ return void 0;
13764
+ }
13765
+
12956
13766
  // src/compute-engine/library/collections.ts
12957
13767
  var DEFAULT_LINSPACE_COUNT = 50;
13768
+ var SET_BASE_HANDLERS = basicIndexedCollectionHandlers();
12958
13769
  var COLLECTIONS_LIBRARY = {
12959
13770
  //
12960
13771
  // Data Structures
@@ -12977,11 +13788,38 @@ ${lines.join("\n")}`;
12977
13788
  },
12978
13789
  // Extensional set. Elements do not repeat. The order of the elements is not significant.
12979
13790
  // For intensional set, use `Filter` with a condition, e.g. `Filter(RealNumbers, _ > 0)`
13791
+ //
13792
+ // A `Set` expression can also be a set-builder (comprehension), e.g.
13793
+ // `["Set", body, ["Element", k, domain, cond?]]` or
13794
+ // `["Set", body, ["Condition", ...]]` (see `parseSetComprehension()`).
13795
+ // Comprehensions are not literal 2-element sets: their elements are the
13796
+ // substituted bodies over the (filtered) domain.
12980
13797
  Set: {
12981
13798
  complexity: 8200,
12982
13799
  signature: "(any*) -> set",
12983
- type: (ops, { engine: _ce }) => parseType(`set<${BoxedType.widen(...ops.map((op) => op.type))}>`),
13800
+ type: (ops, { engine: _ce }) => {
13801
+ if (parseSetComprehension(ops) !== null) return parseType("set");
13802
+ return parseType(`set<${BoxedType.widen(...ops.map((op) => op.type))}>`);
13803
+ },
12984
13804
  canonical: canonicalSet,
13805
+ // The `lazy` flag suppresses the default operand evaluation: evaluating
13806
+ // the operands of a comprehension would mangle its indexing set (e.g.
13807
+ // the condition `gcd(n,k) = 1` with a free `k` evaluates to `False`).
13808
+ // Literal elements are evaluated explicitly in the `evaluate` handler.
13809
+ lazy: true,
13810
+ evaluate: (ops, { engine: ce, numericApproximation, materialization }) => {
13811
+ const comp = parseSetComprehension(ops);
13812
+ if (comp !== null) {
13813
+ const elements = enumerateSetComprehension(comp);
13814
+ if (elements === void 0 || elements.length > MAX_SIZE_EAGER_COLLECTION)
13815
+ return void 0;
13816
+ return ce.function("Set", elements);
13817
+ }
13818
+ return ce.function(
13819
+ "Set",
13820
+ ops.map((op) => op.evaluate({ numericApproximation, materialization }))
13821
+ );
13822
+ },
12985
13823
  eq: (a, b) => {
12986
13824
  if (a.operator !== b.operator) return false;
12987
13825
  if (!isFunction2(a) || !isFunction2(b)) return false;
@@ -12990,10 +13828,75 @@ ${lines.join("\n")}`;
12990
13828
  return a.ops.every(has);
12991
13829
  },
12992
13830
  collection: {
12993
- ...basicIndexedCollectionHandlers(),
13831
+ ...SET_BASE_HANDLERS,
12994
13832
  // A set is not indexable
12995
13833
  at: void 0,
12996
- indexWhere: void 0
13834
+ indexWhere: void 0,
13835
+ // A comprehension computes its elements on demand
13836
+ isLazy: (expr) => isFunction2(expr) && parseSetComprehension(expr.ops) !== null,
13837
+ count: (expr) => {
13838
+ if (!isFunction2(expr)) return 0;
13839
+ const comp = parseSetComprehension(expr.ops);
13840
+ if (comp === null) return expr.nops;
13841
+ return enumerateSetComprehension(comp)?.length;
13842
+ },
13843
+ isEmpty: (expr) => {
13844
+ if (!isFunction2(expr)) return true;
13845
+ const comp = parseSetComprehension(expr.ops);
13846
+ if (comp === null) return expr.nops === 0;
13847
+ const elements = enumerateSetComprehension(comp);
13848
+ return elements === void 0 ? void 0 : elements.length === 0;
13849
+ },
13850
+ isFinite: (expr) => {
13851
+ if (!isFunction2(expr)) return true;
13852
+ const comp = parseSetComprehension(expr.ops);
13853
+ if (comp === null) return true;
13854
+ if (enumerateSetComprehension(comp) !== void 0) return true;
13855
+ if (comp.domain?.isFiniteCollection === true) return true;
13856
+ return void 0;
13857
+ },
13858
+ iterator: (expr) => {
13859
+ if (!isFunction2(expr)) return SET_BASE_HANDLERS.iterator(expr);
13860
+ const comp = parseSetComprehension(expr.ops);
13861
+ if (comp === null) return SET_BASE_HANDLERS.iterator(expr);
13862
+ const elements = enumerateSetComprehension(comp);
13863
+ if (elements === void 0) return void 0;
13864
+ let i = 0;
13865
+ return {
13866
+ next: () => i >= elements.length ? { value: void 0, done: true } : { value: elements[i++], done: false }
13867
+ };
13868
+ },
13869
+ // Three-valued membership: `true` when an element matches, `false`
13870
+ // only when every element is definitively different from `target`
13871
+ // (concrete values), `undefined` otherwise — e.g. a symbolic target
13872
+ // (`Element(ω, {-1, 1})`) is indeterminate, not refuted.
13873
+ contains: (expr, target) => {
13874
+ if (!isFunction2(expr)) return void 0;
13875
+ const comp = parseSetComprehension(expr.ops);
13876
+ if (comp !== null) return setComprehensionContains(comp, target);
13877
+ return literalSetContains(expr.ops, target);
13878
+ },
13879
+ elttype: (expr) => {
13880
+ if (!isFunction2(expr)) return SET_BASE_HANDLERS.elttype(expr);
13881
+ const comp = parseSetComprehension(expr.ops);
13882
+ if (comp === null) return SET_BASE_HANDLERS.elttype(expr);
13883
+ const elements = enumerateSetComprehension(comp);
13884
+ if (elements === void 0 || elements.length === 0) return "unknown";
13885
+ return widen(...elements.map((op) => op.type.type));
13886
+ }
13887
+ }
13888
+ },
13889
+ Length: {
13890
+ description: "Number of elements in a collection. Returns undefined for non-collections and for infinite collections.",
13891
+ complexity: 4e3,
13892
+ signature: "(any) -> integer",
13893
+ type: () => "integer",
13894
+ evaluate: ([xs], { engine }) => {
13895
+ if (!xs.isCollection) return void 0;
13896
+ if (xs.isEmptyCollection) return engine.Zero;
13897
+ const n = xs.count;
13898
+ if (n === void 0 || !isFinite(n)) return void 0;
13899
+ return engine.number(n);
12997
13900
  }
12998
13901
  },
12999
13902
  Tuple: {
@@ -13080,7 +13983,12 @@ ${lines.join("\n")}`;
13080
13983
  },
13081
13984
  contains: (expr, target) => {
13082
13985
  const t = target.re;
13986
+ if (Number.isNaN(t))
13987
+ return typeMembership(target, "number") === false ? false : void 0;
13988
+ if (target.im !== 0) return false;
13083
13989
  if (!isFinite(t)) return false;
13990
+ if (isFunction2(expr) && expr.ops.some((op) => Number.isNaN(op.re)))
13991
+ return void 0;
13084
13992
  const [lower, upper, step] = range(expr);
13085
13993
  if (step === 0) return false;
13086
13994
  if (step > 0) {
@@ -13156,13 +14064,23 @@ ${lines.join("\n")}`;
13156
14064
  signature: "(number, number) -> set<real>",
13157
14065
  canonical: ([lo, hi], { engine }) => {
13158
14066
  if (!lo || !hi) return null;
14067
+ const unwrap2 = (op) => {
14068
+ if (isFunction2(op, "Open")) return [op.op1, true];
14069
+ if (isFunction2(op, "Closed")) return [op.op1, false];
14070
+ return [op, false];
14071
+ };
14072
+ const [loVal, loOpen] = unwrap2(lo);
14073
+ const [hiVal, hiOpen] = unwrap2(hi);
13159
14074
  const [lower, upper] = checkTypes(
13160
14075
  engine,
13161
- [lo.canonical, hi.canonical],
14076
+ [loVal.canonical, hiVal.canonical],
13162
14077
  ["number", "number"]
13163
14078
  );
13164
14079
  if (!lower.isValid || !upper.isValid) return null;
13165
- return engine._fn("Interval", [lower, upper]);
14080
+ return engine._fn("Interval", [
14081
+ loOpen ? engine._fn("Open", [lower]) : lower,
14082
+ hiOpen ? engine._fn("Open", [upper]) : upper
14083
+ ]);
13166
14084
  },
13167
14085
  eq: (a, b) => {
13168
14086
  const intervalA = interval(a);
@@ -13197,19 +14115,32 @@ ${lines.join("\n")}`;
13197
14115
  },
13198
14116
  isEmpty: (_expr) => {
13199
14117
  const int = interval(_expr);
13200
- if (!int) return false;
14118
+ if (!int) return void 0;
13201
14119
  if (int.openStart && int.start === int.end) return true;
13202
14120
  if (int.openEnd && int.start === int.end) return true;
13203
14121
  if (int.openStart && int.openEnd) return false;
13204
14122
  return int.start >= int.end;
13205
14123
  },
13206
14124
  isFinite: (_expr) => false,
14125
+ // Three-valued membership: `true` only when both bound checks are
14126
+ // entailed, `false` when a bound check (or the type of the target)
14127
+ // refutes membership, `undefined` otherwise (e.g. symbolic target
14128
+ // with unknown bounds). Endpoints may be ±Infinity.
13207
14129
  contains: (expr, target) => {
13208
14130
  const int = interval(expr);
13209
- if (!int) return false;
13210
- if (int.openStart && target.isLessEqual(int.start)) return false;
13211
- if (int.openEnd && target.isGreaterEqual(int.end)) return false;
13212
- return target.isGreaterEqual(int.start) && target.isLessEqual(int.end);
14131
+ if (!int) return void 0;
14132
+ if (typeMembership(target, "number") === false) return false;
14133
+ const t = target.re;
14134
+ if (!Number.isNaN(t)) {
14135
+ if (target.im !== 0) return false;
14136
+ return intervalContains(int, t);
14137
+ }
14138
+ const aboveLower = int.openStart ? target.isGreater(int.start) : target.isGreaterEqual(int.start);
14139
+ if (aboveLower === false) return false;
14140
+ const belowUpper = int.openEnd ? target.isLess(int.end) : target.isLessEqual(int.end);
14141
+ if (belowUpper === false) return false;
14142
+ if (aboveLower === true && belowUpper === true) return true;
14143
+ return void 0;
13213
14144
  },
13214
14145
  eltsgn: (expr) => {
13215
14146
  const i = interval(expr);
@@ -13249,10 +14180,12 @@ ${lines.join("\n")}`;
13249
14180
  const upper = expr.op2.re;
13250
14181
  let count = expr.op3.re;
13251
14182
  if (!isFinite(count)) count = DEFAULT_LINSPACE_COUNT;
14183
+ count = Math.floor(count);
13252
14184
  if (!isFinite(lower) || !isFinite(upper)) return void 0;
13253
14185
  if (index < 1 || index > count) return void 0;
14186
+ if (count === 1) return expr.engine.number(lower);
13254
14187
  return expr.engine.number(
13255
- lower + (upper - lower) * (index - 1) / count
14188
+ lower + (upper - lower) * (index - 1) / (count - 1)
13256
14189
  );
13257
14190
  },
13258
14191
  iterator: (expr) => {
@@ -13271,6 +14204,8 @@ ${lines.join("\n")}`;
13271
14204
  !isFinite(expr.op3.re) ? DEFAULT_LINSPACE_COUNT : expr.op3.re
13272
14205
  );
13273
14206
  }
14207
+ totalCount = Math.floor(totalCount);
14208
+ const denom = totalCount > 1 ? totalCount - 1 : 1;
13274
14209
  let index = 1;
13275
14210
  return {
13276
14211
  next: () => {
@@ -13279,7 +14214,7 @@ ${lines.join("\n")}`;
13279
14214
  index += 1;
13280
14215
  return {
13281
14216
  value: expr.engine.number(
13282
- lower + (upper - lower) * (index - 1 - 1) / totalCount
14217
+ lower + (upper - lower) * (index - 1 - 1) / denom
13283
14218
  ),
13284
14219
  done: false
13285
14220
  };
@@ -13287,17 +14222,26 @@ ${lines.join("\n")}`;
13287
14222
  };
13288
14223
  },
13289
14224
  contains: (expr, target) => {
13290
- if (!target.type.matches("finite_real")) return false;
13291
- if (!isFunction2(expr)) return false;
13292
14225
  const t = target.re;
14226
+ if (Number.isNaN(t))
14227
+ return typeMembership(target, "number") === false ? false : void 0;
14228
+ if (target.im !== 0) return false;
14229
+ if (!isFinite(t)) return false;
14230
+ if (!isFunction2(expr)) return void 0;
13293
14231
  const lower = expr.op1.re;
13294
14232
  const upper = expr.op2.re;
14233
+ if (Number.isNaN(lower) || Number.isNaN(upper)) return void 0;
13295
14234
  if (t < lower || t > upper) return false;
13296
14235
  let count = expr.op3.re;
13297
14236
  if (!isFinite(count)) count = DEFAULT_LINSPACE_COUNT;
14237
+ count = Math.floor(count);
13298
14238
  if (count === 0) return false;
13299
- const step = (upper - lower) / count;
13300
- return (t - lower) % step === 0;
14239
+ if (count === 1) return t === lower;
14240
+ const step = (upper - lower) / (count - 1);
14241
+ const k = (t - lower) / step;
14242
+ const tol = expr.engine.tolerance;
14243
+ const kRounded = Math.round(k);
14244
+ return kRounded >= 0 && kRounded <= count - 1 && Math.abs(k - kRounded) < tol;
13301
14245
  }
13302
14246
  }
13303
14247
  },
@@ -13316,8 +14260,18 @@ ${lines.join("\n")}`;
13316
14260
  description: ["Return the number of elements in the collection."],
13317
14261
  complexity: 8200,
13318
14262
  signature: "(collection) -> integer",
13319
- evaluate: ([xs], { engine }) => xs.isEmptyCollection ? engine.Zero : engine.number(xs.count),
13320
- sgn: ([xs]) => xs.isEmptyCollection ? "zero" : "positive"
14263
+ evaluate: ([xs], { engine }) => {
14264
+ if (xs.isEmptyCollection) return engine.Zero;
14265
+ const n = xs.count;
14266
+ if (n === void 0) return void 0;
14267
+ return engine.number(n);
14268
+ },
14269
+ sgn: ([xs]) => {
14270
+ const empty = xs.isEmptyCollection;
14271
+ if (empty === true) return "zero";
14272
+ if (empty === false) return "positive";
14273
+ return void 0;
14274
+ }
13321
14275
  },
13322
14276
  IsEmpty: {
13323
14277
  description: ["Return True if the collection is empty, False otherwise."],
@@ -13433,7 +14387,13 @@ ${lines.join("\n")}`;
13433
14387
  },
13434
14388
  collection: {
13435
14389
  isLazy: (_expr) => true,
13436
- count: (_expr) => Infinity,
14390
+ count: (expr) => {
14391
+ if (!isFunction2(expr)) return void 0;
14392
+ if (!expr.op1.isFiniteCollection) return Infinity;
14393
+ let n = 0;
14394
+ for (const _ of expr.each()) n++;
14395
+ return n;
14396
+ },
13437
14397
  contains: (expr, target) => {
13438
14398
  if (!isFunction2(expr)) return false;
13439
14399
  if (!expr.contains(target)) return false;
@@ -13542,24 +14502,26 @@ ${lines.join("\n")}`;
13542
14502
  type: (ops) => parseType(functionResult(ops[1].type.type) ?? "unknown"),
13543
14503
  evaluate: ([collection, fn, initial], { engine: ce }) => {
13544
14504
  if (!collection.isFiniteCollection) return void 0;
14505
+ const hasInitial = initial !== void 0;
13545
14506
  initial ??= ce.Nothing;
13546
14507
  if (initial.type.matches("real") && collection.type.matches(ce.type("collection<real>"))) {
13547
14508
  const compiled = ce._compile(fn);
13548
- if (compiled.calling !== "lambda" || !compiled.run) return void 0;
13549
- return run(
13550
- (function* () {
13551
- let accumulator = initial.re;
13552
- let first = true;
13553
- for (const item of collection.each()) {
13554
- if (first) accumulator = item.re;
13555
- else accumulator = compiled.run(accumulator, item.re);
13556
- first = false;
13557
- yield;
13558
- }
13559
- return ce.expr(accumulator);
13560
- })(),
13561
- ce._timeRemaining
13562
- );
14509
+ if (compiled.calling === "lambda" && compiled.run) {
14510
+ return run(
14511
+ (function* () {
14512
+ let accumulator = hasInitial ? initial.re : NaN;
14513
+ let first = true;
14514
+ for (const item of collection.each()) {
14515
+ if (first && !hasInitial) accumulator = item.re;
14516
+ else accumulator = compiled.run(accumulator, item.re);
14517
+ first = false;
14518
+ yield;
14519
+ }
14520
+ return ce.expr(accumulator);
14521
+ })(),
14522
+ ce._timeRemaining
14523
+ );
14524
+ }
13563
14525
  }
13564
14526
  const f = applicable(fn);
13565
14527
  return run(
@@ -13622,10 +14584,12 @@ ${lines.join("\n")}`;
13622
14584
  description: [
13623
14585
  "Access an element of an indexed collection.",
13624
14586
  "If the index is negative, it is counted from the end.",
13625
- "Multiple indices can be provided to access nested collections (e.g., matrices)."
14587
+ "Multiple indices can be provided to access nested collections (e.g., matrices).",
14588
+ "If the index is a finite collection of booleans, returns the elements where the mask is True.",
14589
+ "If the index is a finite collection of integers, returns the elements at those indices."
13626
14590
  ],
13627
14591
  complexity: 8200,
13628
- signature: "(value: indexed_collection, index: (number|string)+) -> unknown",
14592
+ signature: "(value: indexed_collection, index: (number|string|indexed_collection)+) -> unknown",
13629
14593
  type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? collectionElementType(xs.type.type) ?? "any",
13630
14594
  evaluate: (ops, { engine: ce }) => {
13631
14595
  let expr = ops[0];
@@ -13636,12 +14600,39 @@ ${lines.join("\n")}`;
13636
14600
  if (!at) return void 0;
13637
14601
  const opAtIndex = ops[index];
13638
14602
  const s = isString(opAtIndex) ? opAtIndex.string : void 0;
13639
- if (s !== void 0) expr = at(expr, s) ?? ce.Nothing;
13640
- else {
13641
- const i = ops[index].re;
13642
- if (!Number.isInteger(i)) return void 0;
13643
- expr = at(expr, i) ?? ce.Nothing;
14603
+ if (s !== void 0) {
14604
+ expr = at(expr, s) ?? ce.Nothing;
14605
+ index += 1;
14606
+ continue;
14607
+ }
14608
+ if (opAtIndex.isCollection && opAtIndex.isFiniteCollection) {
14609
+ const indices = Array.from(opAtIndex.each());
14610
+ const isMask = indices.every((m) => {
14611
+ const name = sym(m);
14612
+ return name === "True" || name === "False";
14613
+ });
14614
+ const picked = [];
14615
+ if (isMask) {
14616
+ indices.forEach((m, i2) => {
14617
+ if (sym(m) !== "True") return;
14618
+ const v = at(expr, i2 + 1);
14619
+ if (v !== void 0) picked.push(v);
14620
+ });
14621
+ } else {
14622
+ for (const m of indices) {
14623
+ const k = m.re;
14624
+ if (!Number.isInteger(k)) return void 0;
14625
+ const v = at(expr, k);
14626
+ if (v !== void 0) picked.push(v);
14627
+ }
14628
+ }
14629
+ expr = ce._fn("List", picked);
14630
+ index += 1;
14631
+ continue;
13644
14632
  }
14633
+ const i = opAtIndex.re;
14634
+ if (!Number.isInteger(i)) return void 0;
14635
+ expr = at(expr, i) ?? ce.Nothing;
13645
14636
  index += 1;
13646
14637
  }
13647
14638
  return expr;
@@ -13652,7 +14643,7 @@ ${lines.join("\n")}`;
13652
14643
  description: ["Return `n` elements from a collection."],
13653
14644
  complexity: 8200,
13654
14645
  signature: "(xs: indexed_collection, count: number) -> indexed_collection",
13655
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
14646
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
13656
14647
  evaluate: (ops, { engine, materialization: eager }) => {
13657
14648
  if (!eager) return void 0;
13658
14649
  const takeExpr = engine._fn("Take", ops);
@@ -13699,7 +14690,7 @@ ${lines.join("\n")}`;
13699
14690
  description: ["Return the collection without the first n elements."],
13700
14691
  complexity: 8200,
13701
14692
  signature: "(xs: indexed_collection, count: number) -> indexed_collection",
13702
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
14693
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
13703
14694
  collection: {
13704
14695
  isLazy: (_expr) => true,
13705
14696
  count: (expr) => {
@@ -13723,10 +14714,13 @@ ${lines.join("\n")}`;
13723
14714
  const [xs, nExpr] = expr.ops;
13724
14715
  const n = toInteger(nExpr) ?? 0;
13725
14716
  if (n <= 0) return xs.each();
14717
+ const count = xs.count;
13726
14718
  let index = n + 1;
13727
14719
  return {
13728
14720
  next: () => {
13729
- const value = expr.op1.at(index++);
14721
+ if (count !== void 0 && index > count)
14722
+ return { value: void 0, done: true };
14723
+ const value = xs.at(index++);
13730
14724
  if (value === void 0) return { value: void 0, done: true };
13731
14725
  return { value, done: false };
13732
14726
  }
@@ -13737,7 +14731,13 @@ ${lines.join("\n")}`;
13737
14731
  if (!isFunction2(expr)) return void 0;
13738
14732
  const [xs, nExpr] = expr.ops;
13739
14733
  const n = toInteger(nExpr) ?? 0;
13740
- if (n <= 0) return void 0;
14734
+ if (n <= 0) return xs.at(index);
14735
+ if (index < 0) {
14736
+ const count = xs.count;
14737
+ if (count !== void 0 && -index > count - n) return void 0;
14738
+ return xs.at(index);
14739
+ }
14740
+ if (index < 1) return void 0;
13741
14741
  return xs.at(index + n);
13742
14742
  }
13743
14743
  }
@@ -13819,11 +14819,15 @@ ${lines.join("\n")}`;
13819
14819
  iterator: (expr) => {
13820
14820
  if (!isFunction2(expr))
13821
14821
  return { next: () => ({ value: void 0, done: true }) };
14822
+ const op1 = expr.op1;
14823
+ const count = op1.count;
14824
+ let index = 2;
13822
14825
  return {
13823
14826
  next: () => {
13824
- let index = 1;
13825
- const value = expr.op1.at(index > 0 ? index + 1 : index);
13826
- if (!value) return { value: void 0, done: true };
14827
+ if (count !== void 0 && index > count)
14828
+ return { value: void 0, done: true };
14829
+ const value = op1.at(index);
14830
+ if (value === void 0) return { value: void 0, done: true };
13827
14831
  index += 1;
13828
14832
  return { value, done: false };
13829
14833
  }
@@ -13895,17 +14899,24 @@ ${lines.join("\n")}`;
13895
14899
  ],
13896
14900
  complexity: 8200,
13897
14901
  signature: "(value: indexed_collection, start: number, end: number) -> list",
13898
- type: ([xs]) => parseType(`list<${collectionElementType(xs.type.type)}>`),
14902
+ type: ([xs]) => parseType(
14903
+ `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`
14904
+ ),
13899
14905
  collection: {
13900
14906
  isLazy: (_expr) => true,
13901
14907
  count: (expr) => {
13902
14908
  if (!isFunction2(expr)) return void 0;
13903
- const start = toInteger(expr.op2) ?? 1;
13904
14909
  const count = expr.op1.count;
13905
14910
  if (count === void 0) return void 0;
13906
- const end = toInteger(expr.op3) ?? count;
13907
- if (start < 1) return Math.max(0, end + start - 1);
13908
- return Math.max(0, Math.min(end, count) - start + 1);
14911
+ let start = toInteger(expr.op2) ?? 1;
14912
+ if (start < 1) start = count + 1 + start;
14913
+ if (start < 1) start = 1;
14914
+ if (start > count) return 0;
14915
+ let end = toInteger(expr.op3) ?? count;
14916
+ if (end < 1) end = count + 1 + end;
14917
+ if (end < 1) end = 1;
14918
+ if (end > count) end = count;
14919
+ return Math.max(0, end - start + 1);
13909
14920
  },
13910
14921
  isFinite: (_expr) => true,
13911
14922
  at: (expr, index) => {
@@ -13921,6 +14932,11 @@ ${lines.join("\n")}`;
13921
14932
  if (end < 1) end = count + 1 + end;
13922
14933
  if (end < 1) end = 1;
13923
14934
  if (end > count) end = count;
14935
+ const length = end - start + 1;
14936
+ if (length <= 0) return void 0;
14937
+ if (index < 0) index = length + 1 + index;
14938
+ if (index < 1 || index > length) return void 0;
14939
+ return expr.op1.at(start + index - 1);
13924
14940
  },
13925
14941
  iterator: (expr) => {
13926
14942
  if (!isFunction2(expr))
@@ -14184,7 +15200,7 @@ ${lines.join("\n")}`;
14184
15200
  for (const item of xs.each()) {
14185
15201
  const pred = sym(f([item]));
14186
15202
  if (pred === "True") indices.push(ce.number(index));
14187
- if (pred !== "False")
15203
+ else if (pred !== "False")
14188
15204
  throw new Error(
14189
15205
  `Filter predicate must return "True" or "False". ${spellCheckMessage(
14190
15206
  fn
@@ -14227,16 +15243,26 @@ ${lines.join("\n")}`;
14227
15243
  },
14228
15244
  // Randomize the order of the elements in the collection.
14229
15245
  Shuffle: {
14230
- description: "Randomize the order of the elements in the collection.",
15246
+ description: "Randomize the order of the elements in the collection. With an optional `seed` argument, the shuffle is deterministic.",
14231
15247
  complexity: 8200,
14232
- signature: "(indexed_collection) -> indexed_collection",
15248
+ signature: "(indexed_collection, real?) -> indexed_collection",
14233
15249
  type: (ops) => ops[0].type,
14234
- evaluate: ([xs], { engine: ce }) => {
15250
+ evaluate: ([xs, seedOp], { engine: ce }) => {
14235
15251
  if (!xs.isFiniteCollection) return void 0;
14236
15252
  const data = Array.from(xs.each());
14237
- for (let i = data.length - 1; i > 0; i--) {
14238
- const j = Math.floor(Math.random() * (i + 1));
14239
- [data[i], data[j]] = [data[j], data[i]];
15253
+ const seed = seedOp?.re;
15254
+ if (seed !== void 0 && !Number.isNaN(seed)) {
15255
+ let s = seed;
15256
+ for (let i = data.length - 1; i > 0; i--) {
15257
+ const j = Math.floor(deterministicRandom(s) * (i + 1));
15258
+ [data[i], data[j]] = [data[j], data[i]];
15259
+ s = nextSeed(s);
15260
+ }
15261
+ } else {
15262
+ for (let i = data.length - 1; i > 0; i--) {
15263
+ const j = Math.floor(Math.random() * (i + 1));
15264
+ [data[i], data[j]] = [data[j], data[i]];
15265
+ }
14240
15266
  }
14241
15267
  return ce.function(xs.operator, data);
14242
15268
  }
@@ -14303,7 +15329,9 @@ ${lines.join("\n")}`;
14303
15329
  if (t === "string")
14304
15330
  return parseType(`tuple<list<string>, list<integer>>`);
14305
15331
  return parseType(
14306
- `tuple<list<${collectionElementType(t)}>, list<integer>>`
15332
+ `tuple<list<${typeToString(
15333
+ collectionElementType(t) ?? "any"
15334
+ )}>, list<integer>>`
14307
15335
  );
14308
15336
  },
14309
15337
  evaluate: (ops, { engine: ce }) => {
@@ -14319,7 +15347,7 @@ ${lines.join("\n")}`;
14319
15347
  description: "Return a list of the unique elements of the collection.",
14320
15348
  complexity: 8200,
14321
15349
  signature: "(collection) -> list",
14322
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
15350
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
14323
15351
  evaluate: (ops, { engine: ce }) => {
14324
15352
  if (!ops[0].isFiniteCollection) return void 0;
14325
15353
  const [values, _counts] = tally(ops[0]);
@@ -14331,7 +15359,7 @@ ${lines.join("\n")}`;
14331
15359
  wikidata: "Q381060",
14332
15360
  complexity: 8200,
14333
15361
  signature: "(collection, integer | function) -> list",
14334
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
15362
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
14335
15363
  evaluate: ([xs, arg], { engine: ce }) => {
14336
15364
  if (!xs.isFiniteCollection) return void 0;
14337
15365
  const k = toInteger(arg);
@@ -14421,11 +15449,25 @@ ${lines.join("\n")}`;
14421
15449
  count: zipCount,
14422
15450
  isFinite: (expr) => {
14423
15451
  if (!isFunction2(expr)) return void 0;
14424
- return expr.ops.every((x) => x.isFiniteCollection);
15452
+ if (expr.nops === 0) return true;
15453
+ let anyUnknown = false;
15454
+ for (const x of expr.ops) {
15455
+ const f = x.isFiniteCollection;
15456
+ if (f === true) return true;
15457
+ if (f === void 0) anyUnknown = true;
15458
+ }
15459
+ return anyUnknown ? void 0 : false;
14425
15460
  },
14426
15461
  isEmpty: (expr) => {
14427
15462
  if (!isFunction2(expr)) return void 0;
14428
- return expr.nops === 0 || expr.ops.every((x) => x.isEmptyCollection);
15463
+ if (expr.nops === 0) return true;
15464
+ let anyUnknown = false;
15465
+ for (const x of expr.ops) {
15466
+ const e = x.isEmptyCollection;
15467
+ if (e === true) return true;
15468
+ if (e === void 0) anyUnknown = true;
15469
+ }
15470
+ return anyUnknown ? void 0 : false;
14429
15471
  },
14430
15472
  iterator: (expr) => {
14431
15473
  if (!isFunction2(expr))
@@ -14505,32 +15547,74 @@ ${lines.join("\n")}`;
14505
15547
  }
14506
15548
  }
14507
15549
  },
14508
- // Repeat(x) -> [x, x, ...]
14509
- // This is an infinite series. Can use Take(Repeat(x), n) to get a finite series
14510
- // x is evaluated once. Although could use Hold()?
14511
- // So that First(Repeat(Hold(Random(5))), 10) would return 10 random numbers...
15550
+ // Repeat(x) -> [x, x, ...] — infinite sequence
15551
+ // Repeat(x, n) -> [x, x, ..., x] — finite list of n copies
14512
15552
  Repeat: {
14513
- description: "Produce an infinite sequence by repeating a single value.",
15553
+ 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.",
14514
15554
  complexity: 8200,
14515
- signature: "(value: any) -> list",
15555
+ signature: "(value: any, count: integer?) -> list",
15556
+ evaluate: (ops, { engine }) => {
15557
+ if (ops.length !== 2) return void 0;
15558
+ const raw = toInteger(ops[1]);
15559
+ if (raw === null) return void 0;
15560
+ const n = Math.max(0, raw);
15561
+ if (n > engine.maxCollectionSize) return void 0;
15562
+ return engine._fn("List", Array(n).fill(ops[0]));
15563
+ },
14516
15564
  collection: {
14517
- isLazy: (_expr) => true,
14518
- count: () => Infinity,
14519
- isEmpty: (_expr) => false,
14520
- // Never empty
14521
- isFinite: () => false,
14522
- // Infinite collection
15565
+ isLazy: (expr) => isFunction2(expr) && expr.ops?.length === 1,
15566
+ count: (expr) => {
15567
+ if (!isFunction2(expr)) return void 0;
15568
+ if (expr.ops?.length === 2) {
15569
+ const n = toInteger(expr.op2);
15570
+ return n !== null ? Math.max(0, n) : void 0;
15571
+ }
15572
+ return Infinity;
15573
+ },
15574
+ isEmpty: (expr) => {
15575
+ if (!isFunction2(expr)) return void 0;
15576
+ if (expr.ops?.length === 2) {
15577
+ const n = toInteger(expr.op2);
15578
+ return n !== null ? n <= 0 : void 0;
15579
+ }
15580
+ return false;
15581
+ },
15582
+ isFinite: (expr) => isFunction2(expr) && expr.ops?.length === 2,
14523
15583
  contains: (expr, target) => {
14524
15584
  if (!isFunction2(expr)) return false;
15585
+ if (expr.ops?.length === 2) {
15586
+ const n = toInteger(expr.op2);
15587
+ if (n !== null && n <= 0) return false;
15588
+ }
14525
15589
  return expr.op1.isSame(target);
14526
15590
  },
14527
15591
  iterator: (expr) => {
14528
15592
  if (!isFunction2(expr))
14529
15593
  return { next: () => ({ value: void 0, done: true }) };
15594
+ if (expr.ops?.length === 2) {
15595
+ const n = toInteger(expr.op2);
15596
+ if (n === null) {
15597
+ return { next: () => ({ value: void 0, done: true }) };
15598
+ }
15599
+ const count = Math.max(0, n);
15600
+ let i = 0;
15601
+ return {
15602
+ next: () => i++ < count ? { value: expr.op1, done: false } : { value: void 0, done: true }
15603
+ };
15604
+ }
14530
15605
  return { next: () => ({ value: expr.op1, done: false }) };
14531
15606
  },
14532
- at: (expr, _index) => {
15607
+ // at is 1-based (consistent with Range, Take, and other collection handlers)
15608
+ at: (expr, index) => {
14533
15609
  if (!isFunction2(expr)) return void 0;
15610
+ if (typeof index !== "number") return void 0;
15611
+ if (expr.ops?.length === 2) {
15612
+ const n = toInteger(expr.op2);
15613
+ const count = n !== null ? Math.max(0, n) : 0;
15614
+ if (index < 1 || index > count) return void 0;
15615
+ } else {
15616
+ if (index < 1) return void 0;
15617
+ }
14534
15618
  return expr.op1;
14535
15619
  }
14536
15620
  }
@@ -14543,9 +15627,22 @@ ${lines.join("\n")}`;
14543
15627
  signature: "(list) -> list",
14544
15628
  collection: {
14545
15629
  isLazy: (_expr) => true,
14546
- count: () => Infinity,
14547
- isEmpty: (expr) => expr.isEmptyCollection,
14548
- isFinite: (expr) => !expr.isEmptyCollection,
15630
+ // Cycling a non-empty collection is infinite; cycling an empty one is
15631
+ // empty. Inspect the *underlying* collection (`op1`) reading
15632
+ // `expr.isEmptyCollection`/`expr.isFiniteCollection` here would re-enter
15633
+ // these same handlers and recurse infinitely.
15634
+ count: (expr) => {
15635
+ if (!isFunction2(expr)) return void 0;
15636
+ return expr.op1.isEmptyCollection ? 0 : Infinity;
15637
+ },
15638
+ isEmpty: (expr) => {
15639
+ if (!isFunction2(expr)) return void 0;
15640
+ return expr.op1.isEmptyCollection;
15641
+ },
15642
+ isFinite: (expr) => {
15643
+ if (!isFunction2(expr)) return void 0;
15644
+ return expr.op1.isEmptyCollection;
15645
+ },
14549
15646
  contains: (expr, target) => {
14550
15647
  if (!isFunction2(expr)) return false;
14551
15648
  return expr.op1.contains(target) ?? false;
@@ -14559,7 +15656,7 @@ ${lines.join("\n")}`;
14559
15656
  return { next: () => ({ value: void 0, done: true }) };
14560
15657
  return {
14561
15658
  next: () => {
14562
- const i = (index - 1 - 1) % l + 1;
15659
+ const i = (index - 1) % l + 1;
14563
15660
  const value = expr.op1.at(i);
14564
15661
  if (value === void 0) return { value: void 0, done: true };
14565
15662
  index += 1;
@@ -14681,7 +15778,7 @@ ${lines.join("\n")}`;
14681
15778
  evaluate: (ops, { engine: ce }) => {
14682
15779
  const elements = [];
14683
15780
  for (const xs of ops) {
14684
- if (xs.isCollection) elements.push(xs);
15781
+ if (!xs.isCollection) elements.push(xs);
14685
15782
  else {
14686
15783
  if (!xs.isFiniteCollection) return void 0;
14687
15784
  elements.push(...Array.from(xs.each()));
@@ -14697,7 +15794,7 @@ ${lines.join("\n")}`;
14697
15794
  evaluate: (ops, { engine: ce }) => {
14698
15795
  const elements = [];
14699
15796
  for (const xs of ops) {
14700
- if (xs.isCollection) elements.push(xs);
15797
+ if (!xs.isCollection) elements.push(xs);
14701
15798
  else {
14702
15799
  if (!xs.isFiniteCollection) return void 0;
14703
15800
  elements.push(...Array.from(xs.each()));
@@ -14790,11 +15887,129 @@ ${lines.join("\n")}`;
14790
15887
  return ce._fn("List", ops);
14791
15888
  }
14792
15889
  function canonicalSet(ops, { engine }) {
15890
+ ops = ops.map((op) => op.canonical);
15891
+ if (parseSetComprehension(ops) !== null) return engine._fn("Set", [...ops]);
14793
15892
  const set = [];
14794
15893
  const has = (x) => set.some((y) => y.isSame(x));
14795
15894
  for (const op of ops) if (!has(op)) set.push(op);
14796
15895
  return engine._fn("Set", set);
14797
15896
  }
15897
+ function parseSetComprehension(ops) {
15898
+ if (ops.length !== 2) return null;
15899
+ const [body, spec] = ops;
15900
+ const canon = (x) => x.isCanonical ? x : x.canonical;
15901
+ if (isFunction2(spec, "Element") && spec.nops >= 2) {
15902
+ if (!isSymbol2(spec.op1)) return null;
15903
+ const v = spec.op1.symbol;
15904
+ if (!body.has(v)) return null;
15905
+ const cond = spec.nops >= 3 && sym(spec.op3) !== "Nothing" ? spec.op3 : void 0;
15906
+ return { body, variable: v, domain: spec.op2, condition: cond };
15907
+ }
15908
+ if (isFunction2(spec, "Condition") && spec.nops >= 1) {
15909
+ const pred = spec.op1;
15910
+ if (isFunction2(body, "Element") && body.nops === 2 && isSymbol2(body.op1)) {
15911
+ return {
15912
+ body: body.op1,
15913
+ variable: body.op1.symbol,
15914
+ domain: canon(body.op2),
15915
+ condition: canon(pred)
15916
+ };
15917
+ }
15918
+ if (isFunction2(pred, "Element") && pred.nops === 2 && isSymbol2(pred.op1)) {
15919
+ const v = pred.op1.symbol;
15920
+ if (body.has(v))
15921
+ return {
15922
+ body,
15923
+ variable: v,
15924
+ domain: canon(pred.op2),
15925
+ condition: void 0
15926
+ };
15927
+ }
15928
+ if (isFunction2(pred, "And")) {
15929
+ const memberships = pred.ops.filter(
15930
+ (x) => isFunction2(x, "Element") && x.nops === 2 && isSymbol2(x.op1) && body.has(x.op1.symbol)
15931
+ );
15932
+ const membership = memberships.length === 1 ? memberships[0] : void 0;
15933
+ if (membership && isFunction2(membership, "Element") && isSymbol2(membership.op1)) {
15934
+ const rest = pred.ops.filter((x) => x !== membership).map(canon);
15935
+ const ce = body.engine;
15936
+ const cond = rest.length === 0 ? void 0 : rest.length === 1 ? rest[0] : ce._fn("And", rest);
15937
+ return {
15938
+ body,
15939
+ variable: membership.op1.symbol,
15940
+ domain: canon(membership.op2),
15941
+ condition: cond
15942
+ };
15943
+ }
15944
+ }
15945
+ return {
15946
+ body,
15947
+ variable: isSymbol2(body) ? body.symbol : void 0,
15948
+ domain: void 0,
15949
+ condition: pred
15950
+ };
15951
+ }
15952
+ return null;
15953
+ }
15954
+ function enumerateSetComprehension(comp) {
15955
+ const { body, variable, domain, condition } = comp;
15956
+ if (variable === void 0 || domain === void 0) return void 0;
15957
+ const ce = body.engine;
15958
+ const extract = (dom) => extractFiniteDomainWithReason(
15959
+ ce._fn("Element", [
15960
+ ce.symbol(variable),
15961
+ dom,
15962
+ ...condition ? [condition] : []
15963
+ ]),
15964
+ ce
15965
+ );
15966
+ let result = extract(domain);
15967
+ if (result.status !== "success") {
15968
+ const evaluatedDomain = domain.evaluate();
15969
+ if (!evaluatedDomain.isSame(domain)) result = extract(evaluatedDomain);
15970
+ }
15971
+ if (result.status !== "success") return void 0;
15972
+ const isIdentity = isSymbol2(body) && body.symbol === variable;
15973
+ const elements = [];
15974
+ for (const value of result.values) {
15975
+ const x = isIdentity ? value : body.subs({ [variable]: value }).evaluate();
15976
+ if (!elements.some((y) => y.isSame(x))) elements.push(x);
15977
+ }
15978
+ return elements;
15979
+ }
15980
+ function literalSetContains(ops, target) {
15981
+ let indeterminate = false;
15982
+ for (const op of ops) {
15983
+ if (target.isSame(op)) return true;
15984
+ if (isNumber(target) && isNumber(op)) {
15985
+ const eq2 = target.isEqual(op);
15986
+ if (eq2 === true) return true;
15987
+ if (eq2 !== false) indeterminate = true;
15988
+ } else if (isString(target) && isString(op)) {
15989
+ } else {
15990
+ indeterminate = true;
15991
+ }
15992
+ }
15993
+ return indeterminate ? void 0 : false;
15994
+ }
15995
+ function setComprehensionContains(comp, target) {
15996
+ const elements = enumerateSetComprehension(comp);
15997
+ if (elements !== void 0) return literalSetContains(elements, target);
15998
+ if (comp.domain !== void 0 && comp.variable !== void 0 && isSymbol2(comp.body) && comp.body.symbol === comp.variable) {
15999
+ const inDomain = comp.domain.contains(target);
16000
+ if (inDomain === false) return false;
16001
+ let condition = true;
16002
+ if (comp.condition !== void 0) {
16003
+ if (isNumber(target) || isString(target)) {
16004
+ const result = comp.condition.subs({ [comp.variable]: target }).evaluate();
16005
+ condition = sym(result) === "True" ? true : sym(result) === "False" ? false : void 0;
16006
+ } else condition = void 0;
16007
+ }
16008
+ if (condition === false) return false;
16009
+ if (inDomain === true && condition === true) return true;
16010
+ }
16011
+ return void 0;
16012
+ }
14798
16013
  function tally(collection) {
14799
16014
  const values = [];
14800
16015
  const counts = [];
@@ -15034,7 +16249,11 @@ ${lines.join("\n")}`;
15034
16249
  op[1]
15035
16250
  )}`;
15036
16251
  } else {
15037
- resultStr = args.map((arg) => _BaseCompiler.compile(arg, target, op[1])).join(` ${op[0]} `);
16252
+ const rightAssoc = h === "Power";
16253
+ resultStr = args.map((arg, i) => {
16254
+ const operandPrec = rightAssoc && i < args.length - 1 ? op[1] + 1 : op[1];
16255
+ return _BaseCompiler.compile(arg, target, operandPrec);
16256
+ }).join(` ${op[0]} `);
15038
16257
  }
15039
16258
  return op[1] < prec ? `(${resultStr})` : resultStr;
15040
16259
  }
@@ -15239,6 +16458,13 @@ ${lines.join("\n")}`;
15239
16458
  * GLSL (no dynamic arrays, no push). A compile-time error is thrown.
15240
16459
  * TODO(E3-GLSL): support GLSL multi-Element via a pre-declared fixed-size
15241
16460
  * array or by unrolling when bounds are known at compile time.
16461
+ *
16462
+ * Known issue (imperative form): the IIFE generated by form (1) has no
16463
+ * `return` statement, so `Loop(body, Element(i, Range(lo, hi)))` compiled
16464
+ * to JS evaluates to `undefined` at runtime, while CE evaluation returns a
16465
+ * `List` of body values. See `test/compute-engine/a1-c1-compile-parity.test.ts`
16466
+ * ("Loop compiles in JS") for the verify-only test that locks in the
16467
+ * current behavior.
15242
16468
  */
15243
16469
  static compileForLoop(args, target) {
15244
16470
  if (!args[0]) throw new Error("Loop: no body");
@@ -15720,6 +16946,17 @@ ${lines.join("\n")}`;
15720
16946
  `Compilation fallback for "${expr.operator}" (target: ${options?.to ?? "javascript"}): ${e.message}`
15721
16947
  );
15722
16948
  const ce = expr.engine;
16949
+ const target = options?.to ?? "javascript";
16950
+ if (isFunction2(expr, "Function")) {
16951
+ const lambdaRun = ((...args) => ce.function("Apply", [expr, ...args.map((a) => ce.box(a))]).evaluate().re);
16952
+ return {
16953
+ target,
16954
+ success: false,
16955
+ code: "",
16956
+ calling: "lambda",
16957
+ run: lambdaRun
16958
+ };
16959
+ }
15723
16960
  const fallbackRun = ((vars) => {
15724
16961
  ce.pushScope();
15725
16962
  try {
@@ -15732,7 +16969,7 @@ ${lines.join("\n")}`;
15732
16969
  }
15733
16970
  });
15734
16971
  return {
15735
- target: options?.to ?? "javascript",
16972
+ target,
15736
16973
  success: false,
15737
16974
  code: "",
15738
16975
  calling: "expression",
@@ -15786,6 +17023,11 @@ ${lines.join("\n")}`;
15786
17023
  if (symbolic.length === 1) return symbolic[0];
15787
17024
  return symbolic.join(op === "+" ? " + " : " * ");
15788
17025
  }
17026
+ function parenthesizeFactor(expr, code) {
17027
+ if (isFunction2(expr, "Add") || isFunction2(expr, "Subtract"))
17028
+ return `(${code})`;
17029
+ return code;
17030
+ }
15789
17031
  function tryGetComplexParts(expr, compile2) {
15790
17032
  if (isSymbol2(expr, "ImaginaryUnit")) {
15791
17033
  return { re: null, im: "1.0" };
@@ -15810,7 +17052,9 @@ ${lines.join("\n")}`;
15810
17052
  if (remaining.length === 0) {
15811
17053
  return { re: null, im: formatFloat(iScale) };
15812
17054
  }
15813
- const compiledFactors = remaining.map((r) => compile2(r));
17055
+ const compiledFactors = remaining.map(
17056
+ (r) => parenthesizeFactor(r, compile2(r))
17057
+ );
15814
17058
  if (iScale !== 1) compiledFactors.unshift(formatFloat(iScale));
15815
17059
  const imCode = foldTerms(compiledFactors, "1.0", "*");
15816
17060
  return { re: null, im: imCode };
@@ -19327,9 +20571,14 @@ ${lines.join("\n")}`;
19327
20571
  ];
19328
20572
  function gammaln(z) {
19329
20573
  if (z < 0) return NaN;
20574
+ let shift = 0;
20575
+ while (z < 10) {
20576
+ shift += Math.log(z);
20577
+ z += 1;
20578
+ }
19330
20579
  const pi = Math.PI;
19331
20580
  const z3 = z * z * z;
19332
- return z * Math.log(z) - z - 0.5 * Math.log(z) + 0.5 * Math.log(2 * pi) + 1 / (12 * z) - 1 / (360 * z3) + 1 / (1260 * z3 * z * z);
20581
+ return z * Math.log(z) - z - 0.5 * Math.log(z) + 0.5 * Math.log(2 * pi) + 1 / (12 * z) - 1 / (360 * z3) + 1 / (1260 * z3 * z * z) - shift;
19333
20582
  }
19334
20583
  function gamma(z) {
19335
20584
  if (z < 0.5) return Math.PI / (Math.sin(Math.PI * z) * gamma(1 - z));
@@ -19340,31 +20589,62 @@ ${lines.join("\n")}`;
19340
20589
  const t = z + gammaG + 0.5;
19341
20590
  return Math.sqrt(2 * Math.PI) * Math.pow(t, z + 0.5) * Math.exp(-t) * x;
19342
20591
  }
20592
+ function erfInvApprox(x) {
20593
+ const a = 0.147;
20594
+ const ln1mx2 = Math.log(1 - x * x);
20595
+ const b = 2 / (Math.PI * a) + ln1mx2 / 2;
20596
+ return Math.sign(x) * Math.sqrt(Math.sqrt(b * b - ln1mx2 / a) - b);
20597
+ }
19343
20598
  function erfInv(x) {
19344
- const pi = Math.PI;
19345
- const pi2 = pi * pi;
19346
- const pi3 = pi2 * pi;
19347
- const x2 = x * x;
19348
- const x3 = x * x2;
19349
- const x5 = x3 * x2;
19350
- const x7 = x5 * x2;
19351
- return Math.sqrt(pi) / 2 * (x + pi / 12 * x3 + 7 * pi2 / 480 * x5 + 127 * pi3 / 40320 * x7 + 4369 * pi2 * pi2 / 5806080 * x7 * x2 + 34807 * pi3 * pi2 / 182476800 * x7 * x2 * x2);
20599
+ if (Number.isNaN(x) || x < -1 || x > 1) return NaN;
20600
+ if (x === 0) return 0;
20601
+ if (x === 1) return Infinity;
20602
+ if (x === -1) return -Infinity;
20603
+ const sign2 = x < 0 ? -1 : 1;
20604
+ const ax = Math.abs(x);
20605
+ let y = erfInvApprox(ax);
20606
+ const c = Math.sqrt(Math.PI) / 2;
20607
+ for (let i = 0; i < 4; i++) y -= (erf(y) - ax) * c * Math.exp(y * y);
20608
+ return sign2 * y;
19352
20609
  }
19353
20610
  function erfc(x) {
19354
- return 1 - erf(x);
20611
+ if (Number.isNaN(x)) return NaN;
20612
+ if (!Number.isFinite(x)) return x > 0 ? 0 : 2;
20613
+ if (x < 0) return 2 - erfc(-x);
20614
+ if (x < 2) return 1 - erf(x);
20615
+ const tiny = 1e-300;
20616
+ let f = x === 0 ? tiny : x;
20617
+ let c = f;
20618
+ let d = 0;
20619
+ for (let k = 1; k <= 500; k++) {
20620
+ const a = k / 2;
20621
+ d = x + a * d;
20622
+ if (d === 0) d = tiny;
20623
+ d = 1 / d;
20624
+ c = x + a / c;
20625
+ if (c === 0) c = tiny;
20626
+ const delta = c * d;
20627
+ f *= delta;
20628
+ if (Math.abs(delta - 1) < 1e-17) break;
20629
+ }
20630
+ return Math.exp(-x * x) / (Math.sqrt(Math.PI) * f);
19355
20631
  }
19356
20632
  function erf(x) {
19357
- const a1 = 0.254829592;
19358
- const a2 = -0.284496736;
19359
- const a3 = 1.421413741;
19360
- const a4 = -1.453152027;
19361
- const a5 = 1.061405429;
19362
- const p = 0.3275911;
20633
+ if (Number.isNaN(x)) return NaN;
20634
+ if (x === 0) return 0;
20635
+ if (!Number.isFinite(x)) return x > 0 ? 1 : -1;
19363
20636
  const sign2 = x < 0 ? -1 : 1;
19364
- x = Math.abs(x);
19365
- const t = 1 / (1 + p * x);
19366
- const y = ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t;
19367
- return sign2 * (1 - y * Math.exp(-x * x));
20637
+ const ax = Math.abs(x);
20638
+ if (ax >= 6) return sign2;
20639
+ const x2 = ax * ax;
20640
+ let term = ax;
20641
+ let sum = ax;
20642
+ for (let n = 1; n < 200; n++) {
20643
+ term *= 2 * x2 / (2 * n + 1);
20644
+ sum += term;
20645
+ if (term < sum * 1e-18) break;
20646
+ }
20647
+ return sign2 * (2 / Math.sqrt(Math.PI)) * Math.exp(-x2) * sum;
19368
20648
  }
19369
20649
  var EULER_MASCHERONI = 0.5772156649015329;
19370
20650
  var BERNOULLI_2K = [
@@ -19950,7 +21230,7 @@ ${lines.join("\n")}`;
19950
21230
  const t = x2 * x2;
19951
21231
  return sign2 * x * x2 * polevl(t, SN) / polevl(t, SD);
19952
21232
  }
19953
- if (x < 36) {
21233
+ if (x < 36974) {
19954
21234
  const x2 = x * x;
19955
21235
  const t = Math.PI * x2;
19956
21236
  const u = 1 / (t * t);
@@ -19975,7 +21255,7 @@ ${lines.join("\n")}`;
19975
21255
  const t = x2 * x2;
19976
21256
  return sign2 * x * polevl(t, CN) / polevl(t, CD);
19977
21257
  }
19978
- if (x < 36) {
21258
+ if (x < 36974) {
19979
21259
  const x2 = x * x;
19980
21260
  const t = Math.PI * x2;
19981
21261
  const u = 1 / (t * t);
@@ -20066,6 +21346,7 @@ ${lines.join("\n")}`;
20066
21346
  function kurtosis(values) {
20067
21347
  let sum = 0;
20068
21348
  let sum2 = 0;
21349
+ let sum3 = 0;
20069
21350
  let sum4 = 0;
20070
21351
  let count = 0;
20071
21352
  for (const op of values) {
@@ -20073,12 +21354,16 @@ ${lines.join("\n")}`;
20073
21354
  if (!Number.isFinite(v)) return NaN;
20074
21355
  sum += v;
20075
21356
  sum2 += v * v;
21357
+ sum3 += v * v * v;
20076
21358
  sum4 += v * v * v * v;
20077
21359
  count++;
20078
21360
  }
20079
21361
  if (count === 0) return NaN;
20080
- const s2 = (sum2 - sum * sum / count) / (count - 1);
20081
- return (sum4 - 4 * sum * sum2 / count + 6 * sum * sum * sum / count / count - 3 * sum * sum * sum * sum / count / count / count) / (s2 * s2);
21362
+ const n = count;
21363
+ const m = sum / n;
21364
+ const m2 = (sum2 - sum * sum / n) / n;
21365
+ const m4 = (sum4 - 4 * m * sum3 + 6 * m * m * sum2 - 4 * m * m * m * sum + n * m * m * m * m) / n;
21366
+ return m4 / (m2 * m2);
20082
21367
  }
20083
21368
  function skewness(values) {
20084
21369
  let sum = 0;
@@ -20094,9 +21379,11 @@ ${lines.join("\n")}`;
20094
21379
  count++;
20095
21380
  }
20096
21381
  if (count === 0) return NaN;
20097
- const s2 = (sum2 - sum * sum / count) / (count - 1);
20098
- const s3 = (sum3 - sum2 * sum / count) / (count - 1);
20099
- return s3 / Math.pow(s2, 3 / 2) * Math.sqrt(count * 1);
21382
+ const n = count;
21383
+ const m = sum / n;
21384
+ const m2 = (sum2 - sum * sum / n) / n;
21385
+ const m3 = (sum3 - 3 * m * sum2 + 3 * m * m * sum - n * m * m * m) / n;
21386
+ return m3 / Math.pow(m2, 3 / 2);
20100
21387
  }
20101
21388
  function mode(values) {
20102
21389
  const counts = {};
@@ -20123,11 +21410,8 @@ ${lines.join("\n")}`;
20123
21410
  return [q1, q2, q3];
20124
21411
  }
20125
21412
  function interquartileRange(values) {
20126
- const sorted = [...values].sort((a, b) => a - b);
20127
- const mid = Math.floor(sorted.length / 2);
20128
- const lower = sorted.slice(0, mid);
20129
- const upper = sorted.slice(mid + 1);
20130
- return median(upper) - median(lower);
21413
+ const [q1, , q3] = quartiles(values);
21414
+ return q3 - q1;
20131
21415
  }
20132
21416
 
20133
21417
  // src/compute-engine/numerics/monte-carlo.ts
@@ -20326,6 +21610,7 @@ ${lines.join("\n")}`;
20326
21610
  return `_SYS.cexp(${compile2(args[0])})`;
20327
21611
  return `Math.exp(${compile2(args[0])})`;
20328
21612
  },
21613
+ First: (args, compile2) => `${compile2(args[0])}[0]`,
20329
21614
  Floor: (args, compile2) => {
20330
21615
  if (BaseCompiler.isIntegerValued(args[0])) return compile2(args[0]);
20331
21616
  return `Math.floor(${compile2(args[0])})`;
@@ -20457,7 +21742,7 @@ ${lines.join("\n")}`;
20457
21742
  if (parseFloat(step) === 1) {
20458
21743
  const fStop = parseFloat(stop);
20459
21744
  const fStart = parseFloat(start);
20460
- if (fStop !== null && fStart !== null) {
21745
+ if (!isNaN(fStop) && !isNaN(fStart)) {
20461
21746
  if (fStop - fStart < 50) {
20462
21747
  return `[${Array.from(
20463
21748
  { length: fStop - fStart + 1 },
@@ -20468,9 +21753,9 @@ ${lines.join("\n")}`;
20468
21753
  }, (_, i) => ${start} + i)`;
20469
21754
  }
20470
21755
  return `Array.from({length: ${stop} - ${start} + 1
20471
- }, (_, i) => ${start} + i)`;
21756
+ }, (_e, i) => ${start} + i)`;
20472
21757
  }
20473
- return `Array.from({length: Math.floor((${stop} - ${start}) / ${step}) + 1}, (_, i) => ${start} + i * ${step})`;
21758
+ return `Array.from({length: Math.floor((${stop} - ${start}) / ${step}) + 1}, (_e, i) => ${start} + i * ${step})`;
20474
21759
  },
20475
21760
  Root: ([arg, exp3], compile2) => {
20476
21761
  if (arg === null) throw new Error("Root: no argument");
@@ -20484,7 +21769,20 @@ ${lines.join("\n")}`;
20484
21769
  if (nConst !== void 0) return `Math.pow(${compile2(arg)}, ${1 / nConst})`;
20485
21770
  return `Math.pow(${compile2(arg)}, 1 / (${compile2(exp3)}))`;
20486
21771
  },
20487
- Random: "Math.random",
21772
+ Random: (args, compile2) => {
21773
+ if (args.length === 0) return "Math.random()";
21774
+ if (args.length === 2) {
21775
+ const m = compile2(args[0]);
21776
+ const n = compile2(args[1]);
21777
+ return `((${m}) + Math.floor(Math.random() * ((${n}) - (${m}))))`;
21778
+ }
21779
+ const arg = args[0];
21780
+ if (BaseCompiler.isIntegerValued(arg)) {
21781
+ return `Math.floor(Math.random() * (${compile2(arg)}))`;
21782
+ }
21783
+ const a = compile2(arg);
21784
+ return `(() => { const _s = (${a}) * 12.9898; const _v = Math.sin(_s) * 43758.5453; return _v - Math.floor(_v); })()`;
21785
+ },
20488
21786
  Round: (args, compile2) => {
20489
21787
  if (BaseCompiler.isIntegerValued(args[0])) return compile2(args[0]);
20490
21788
  return `Math.round(${compile2(args[0])})`;
@@ -20512,6 +21810,7 @@ ${lines.join("\n")}`;
20512
21810
  if (BaseCompiler.isComplexValued(arg)) return `_SYS.csech(${compile2(arg)})`;
20513
21811
  return `1 / Math.cosh(${compile2(arg)})`;
20514
21812
  },
21813
+ Second: (args, compile2) => `${compile2(args[0])}[1]`,
20515
21814
  Heaviside: "_SYS.heaviside",
20516
21815
  Sign: "Math.sign",
20517
21816
  Sinc: "_SYS.sinc",
@@ -20544,6 +21843,7 @@ ${lines.join("\n")}`;
20544
21843
  return `_SYS.ctanh(${compile2(args[0])})`;
20545
21844
  return `Math.tanh(${compile2(args[0])})`;
20546
21845
  },
21846
+ Third: (args, compile2) => `${compile2(args[0])}[2]`,
20547
21847
  Mod: ([a, b], compile2) => {
20548
21848
  if (a === null || b === null) throw new Error("Mod: missing argument");
20549
21849
  const ca = compile2(a);
@@ -21612,6 +22912,14 @@ ${lines.join("\n")}`;
21612
22912
  function gpuVec3(target) {
21613
22913
  return target?.language === "wgsl" ? "vec3f" : "vec3";
21614
22914
  }
22915
+ function gpuNaN(target) {
22916
+ return target?.language === "wgsl" ? "bitcast<f32>(0x7fc00000u)" : "(0.0 / 0.0)";
22917
+ }
22918
+ function gpuConditional(cond, whenTrue, whenFalse, target) {
22919
+ if (target?.language === "wgsl")
22920
+ return `select(${whenFalse}, ${whenTrue}, ${cond})`;
22921
+ return `((${cond}) ? (${whenTrue}) : (${whenFalse}))`;
22922
+ }
21615
22923
  function readStringLiteral(expr) {
21616
22924
  if (!isString(expr)) return null;
21617
22925
  return expr.string?.toLowerCase() ?? null;
@@ -21729,7 +23037,7 @@ ${lines.join("\n")}`;
21729
23037
  const realFactors = args.filter((_, i) => i !== iIndex);
21730
23038
  const v2 = gpuVec2(target);
21731
23039
  if (realFactors.length === 0) return `${v2}(0.0, ${formatFloat(iScale)})`;
21732
- const factors = realFactors.map((f) => compile2(f));
23040
+ const factors = realFactors.map((f) => parenthesizeFactor(f, compile2(f)));
21733
23041
  if (iScale !== 1) factors.unshift(formatFloat(iScale));
21734
23042
  const imCode = foldTerms(factors, "1.0", "*");
21735
23043
  return `${v2}(0.0, ${imCode})`;
@@ -21738,7 +23046,7 @@ ${lines.join("\n")}`;
21738
23046
  const complexCodes = [];
21739
23047
  for (const a of args) {
21740
23048
  if (BaseCompiler.isComplexValued(a)) complexCodes.push(compile2(a));
21741
- else realCodes.push(compile2(a));
23049
+ else realCodes.push(parenthesizeFactor(a, compile2(a)));
21742
23050
  }
21743
23051
  const scalarCode = foldTerms(realCodes, "1.0", "*");
21744
23052
  let result = complexCodes[0];
@@ -21816,13 +23124,23 @@ ${lines.join("\n")}`;
21816
23124
  return `_gpu_ccos(${compile2(args[0])})`;
21817
23125
  return `cos(${compile2(args[0])})`;
21818
23126
  },
21819
- Degrees: "degrees",
23127
+ // CE's `Degrees` converts degrees→radians (Degrees(180) = π), which is
23128
+ // GLSL's `radians()`. GLSL's `degrees()` is the inverse (rad→deg).
23129
+ Degrees: "radians",
21820
23130
  Exp: (args, compile2) => {
21821
23131
  if (BaseCompiler.isComplexValued(args[0]))
21822
23132
  return `_gpu_cexp(${compile2(args[0])})`;
21823
23133
  return `exp(${compile2(args[0])})`;
21824
23134
  },
21825
23135
  Exp2: "exp2",
23136
+ // Component access — assumes the argument compiles to a vec2/vec3/vec4
23137
+ // (the common case for 2D/3D points). For 5+-element tuples that compile
23138
+ // to `float[N]` arrays, swizzle access is invalid GLSL and the shader
23139
+ // will fail to compile; that's an edge case `First`/`Second`/`Third`
23140
+ // aren't designed for. Vec swizzles are identical between GLSL and WGSL.
23141
+ First: (args, compile2) => `${compile2(args[0])}.x`,
23142
+ Second: (args, compile2) => `${compile2(args[0])}.y`,
23143
+ Third: (args, compile2) => `${compile2(args[0])}.z`,
21826
23144
  Floor: (args, compile2) => {
21827
23145
  if (BaseCompiler.isIntegerValued(args[0])) return compile2(args[0]);
21828
23146
  return `floor(${compile2(args[0])})`;
@@ -21837,6 +23155,43 @@ ${lines.join("\n")}`;
21837
23155
  Max: "max",
21838
23156
  Min: "min",
21839
23157
  Mix: "mix",
23158
+ // Control-flow forms — the base compiler's default emits a JS ternary and a
23159
+ // bare `NaN`, neither of which is valid GPU code (WGSL has no `?:`, and no
23160
+ // shader language has a `NaN` identifier). Emit `select(...)` for WGSL and a
23161
+ // language-appropriate NaN.
23162
+ If: (args, compile2, target) => {
23163
+ if (args.length !== 3) throw new Error("If: wrong number of arguments");
23164
+ return gpuConditional(
23165
+ compile2(args[0]),
23166
+ compile2(args[1]),
23167
+ compile2(args[2]),
23168
+ target
23169
+ );
23170
+ },
23171
+ When: (args, compile2, target) => {
23172
+ if (args.length !== 2)
23173
+ throw new Error("When: expected exactly 2 arguments (expr, cond)");
23174
+ if (isSymbol2(args[1], "True")) return `(${compile2(args[0])})`;
23175
+ if (isSymbol2(args[1], "False")) return gpuNaN(target);
23176
+ return gpuConditional(
23177
+ compile2(args[1]),
23178
+ compile2(args[0]),
23179
+ gpuNaN(target),
23180
+ target
23181
+ );
23182
+ },
23183
+ Which: (args, compile2, target) => {
23184
+ if (args.length < 2 || args.length % 2 !== 0)
23185
+ throw new Error("Which: expected condition/value pairs");
23186
+ const build = (i) => {
23187
+ if (i >= args.length) return gpuNaN(target);
23188
+ const cond = args[i];
23189
+ const val = args[i + 1];
23190
+ if (isSymbol2(cond, "True")) return `(${compile2(val)})`;
23191
+ return gpuConditional(compile2(cond), compile2(val), build(i + 2), target);
23192
+ };
23193
+ return build(0);
23194
+ },
21840
23195
  Power: (args, compile2, target) => {
21841
23196
  const base = args[0];
21842
23197
  const exp3 = args[1];
@@ -22300,6 +23655,39 @@ ${lines.join("\n")}`;
22300
23655
  // Sum/Product — unrolled or for-loop
22301
23656
  Sum: (args, compile2, target) => compileGPUSumProduct("Sum", args, compile2, target),
22302
23657
  Product: (args, compile2, target) => compileGPUSumProduct("Product", args, compile2, target),
23658
+ // Range — inline constant array literal (bounds must be compile-time constants)
23659
+ Range: (args, _compile, target) => {
23660
+ if (args.length < 2 || args.length > 3) {
23661
+ throw new Error(
23662
+ "Range: GPU compile expects 2 or 3 arguments (lo, hi, step?)"
23663
+ );
23664
+ }
23665
+ const lo = args[0].re;
23666
+ const hi = args[1].re;
23667
+ const step = args.length === 3 ? args[2].re : 1;
23668
+ if (!Number.isFinite(lo) || !Number.isFinite(hi) || !Number.isFinite(step)) {
23669
+ throw new Error(
23670
+ "Range: GPU compile requires constant numeric bounds (non-constant ranges must be materialized at JS host then uploaded as a uniform)"
23671
+ );
23672
+ }
23673
+ if (step === 0) throw new Error("Range: step cannot be zero");
23674
+ const count = Math.max(0, Math.floor((hi - lo) / step) + 1);
23675
+ if (count === 0) {
23676
+ throw new Error(
23677
+ "Range: empty range (lo > hi for positive step, or lo < hi for negative step)"
23678
+ );
23679
+ }
23680
+ if (count > 256) {
23681
+ throw new Error(
23682
+ `Range: GPU compile inlines ranges up to 256 elements (got ${count})`
23683
+ );
23684
+ }
23685
+ const values = [];
23686
+ for (let i = 0; i < count; i++) values.push(lo + i * step);
23687
+ const isWGSL = target.language === "wgsl";
23688
+ const arrayType = isWGSL ? `array<f32, ${count}>` : `float[${count}]`;
23689
+ return `${arrayType}(${values.map(formatGPUNumber).join(", ")})`;
23690
+ },
22303
23691
  // Loop — GPU for-loop (no IIFE, no let)
22304
23692
  Loop: (args, _compile, target) => {
22305
23693
  if (!args[0]) throw new Error("Loop: no body");
@@ -22328,6 +23716,134 @@ ${lines.join("\n")}`;
22328
23716
  ${bodyCode};
22329
23717
  }`;
22330
23718
  },
23719
+ // Statistical functions
23720
+ /**
23721
+ * GCD of two scalar arguments.
23722
+ *
23723
+ * Uses a preamble helper `_gpu_gcd` (Euclidean algorithm via `mod`).
23724
+ * Only two-argument form is supported in GPU targets.
23725
+ */
23726
+ GCD: (args, compile2) => {
23727
+ if (args.length < 2) throw new Error("GCD: need at least two arguments");
23728
+ if (args.length > 2)
23729
+ throw new Error("GCD: GPU target supports only two-argument GCD");
23730
+ const a = args[0];
23731
+ const b = args[1];
23732
+ if (a === null || b === null) throw new Error("GCD: missing argument");
23733
+ return `_gpu_gcd(${compile2(a)}, ${compile2(b)})`;
23734
+ },
23735
+ /**
23736
+ * Variance of a compile-time-known list.
23737
+ *
23738
+ * Accepts either a single `List(...)` argument or N scalar arguments.
23739
+ * Generates fully inline code: computes mean then sum of squared deviations,
23740
+ * divided by (N-1) for sample variance (matches JS `_SYS.variance`).
23741
+ */
23742
+ Variance: (args, compile2) => {
23743
+ let elems;
23744
+ if (args.length === 1 && isFunction2(args[0], "List")) {
23745
+ elems = args[0].ops;
23746
+ } else if (args.length >= 2) {
23747
+ elems = args;
23748
+ } else {
23749
+ throw new Error(
23750
+ "Variance: GPU target requires a List argument or at least 2 scalar arguments"
23751
+ );
23752
+ }
23753
+ const n = elems.length;
23754
+ if (n < 2) throw new Error("Variance: need at least 2 elements");
23755
+ const compiled = elems.map((e) => compile2(e));
23756
+ const sum = compiled.join(" + ");
23757
+ const mean2 = `((${sum}) / ${formatGPUNumber(n)})`;
23758
+ const sqDiffs = compiled.map((c) => `(${c} - ${mean2}) * (${c} - ${mean2})`).join(" + ");
23759
+ return `((${sqDiffs}) / ${formatGPUNumber(n - 1)})`;
23760
+ },
23761
+ /**
23762
+ * Median of a compile-time-known list.
23763
+ *
23764
+ * Accepts either a single `List(...)` argument or N scalar arguments.
23765
+ * For N ≤ 8: generates a fully unrolled inline sorting network followed by
23766
+ * a middle-element pick. For larger N, throws (too large to inline cleanly).
23767
+ *
23768
+ * The sorting network uses the "odd-even merge sort" comparator pattern
23769
+ * inlined as `min`/`max` calls — no GPU statements required.
23770
+ */
23771
+ Median: (args, compile2) => {
23772
+ let elems;
23773
+ if (args.length === 1 && isFunction2(args[0], "List")) {
23774
+ elems = args[0].ops;
23775
+ } else if (args.length >= 1) {
23776
+ elems = args;
23777
+ } else {
23778
+ throw new Error(
23779
+ "Median: GPU target requires a List argument or at least 1 scalar argument"
23780
+ );
23781
+ }
23782
+ const n = elems.length;
23783
+ if (n === 0) throw new Error("Median: empty list");
23784
+ if (n > 8) {
23785
+ throw new Error(
23786
+ `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.`
23787
+ );
23788
+ }
23789
+ const compiled = elems.map((e) => compile2(e));
23790
+ if (n === 1) return compiled[0];
23791
+ return `_gpu_median_${n}(${compiled.join(", ")})`;
23792
+ },
23793
+ /**
23794
+ * Deterministic pseudorandom for GPU.
23795
+ *
23796
+ * All emitted forms return a GLSL `float` (or WGSL `f32`) so the result
23797
+ * composes with surrounding float arithmetic without explicit casts. The
23798
+ * "integer-bound" forms return an integer-valued float (the result of
23799
+ * `floor`), matching the convention used by `Floor` and other ostensibly
23800
+ * integer-returning operators in this target.
23801
+ *
23802
+ * - 0 args (GLSL only): fall back to a fragment-coord-derived seed.
23803
+ * Only meaningful in fragment shaders (gl_FragCoord is FS-only).
23804
+ * - 0 args (WGSL): throws — WGSL has no built-in fragment coordinate;
23805
+ * caller must provide an explicit seed.
23806
+ * - 1 arg, real-typed: `_gpu_random(seed)` — deterministic float in [0, 1)
23807
+ * - 1 arg, integer-typed: `floor(_gpu_random(float(n)) * float(n))` —
23808
+ * integer-valued float in {0, 1, ..., n-1}. The seed is derived from
23809
+ * `n` itself, so the result is per-pixel-and-n deterministic in GLSL.
23810
+ * - 2 args (integer m, n): float in [m, n), seeded from gl_FragCoord.
23811
+ *
23812
+ * JS-side `Random` has matching semantics (see `library/core.ts`'s
23813
+ * polymorphic dispatch). JS↔GLSL parity is approximate — same seed yields
23814
+ * a similar value, not bit-identical, due to fp64 vs fp32 and platform
23815
+ * `sin` differences.
23816
+ */
23817
+ Random: (args, compile2, target) => {
23818
+ if (args.length === 0) {
23819
+ if (target.language === "wgsl") {
23820
+ throw new Error(
23821
+ "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."
23822
+ );
23823
+ }
23824
+ return "_gpu_random(gl_FragCoord.x + gl_FragCoord.y * 1024.0)";
23825
+ }
23826
+ if (args.length === 1) {
23827
+ const arg = args[0];
23828
+ if (BaseCompiler.isIntegerValued(arg)) {
23829
+ const compiled = compile2(arg);
23830
+ return `floor(_gpu_random(float(${compiled})) * float(${compiled}))`;
23831
+ }
23832
+ return `_gpu_random(${compile2(arg)})`;
23833
+ }
23834
+ if (args.length === 2) {
23835
+ if (target.language === "wgsl") {
23836
+ throw new Error(
23837
+ "Random(m, n): WGSL compile requires explicit seeding. Use a seeded variant or compute the integer range manually."
23838
+ );
23839
+ }
23840
+ const m = compile2(args[0]);
23841
+ const n = compile2(args[1]);
23842
+ const seed = "_gpu_random(gl_FragCoord.x + gl_FragCoord.y * 1024.0)";
23843
+ return `(float(${m}) + floor(${seed} * float((${n}) - (${m}))))`;
23844
+ }
23845
+ throw new Error("Random: GPU compile expects 0, 1, or 2 arguments");
23846
+ },
22331
23847
  // Function (lambda) — not supported in GPU
22332
23848
  Function: () => {
22333
23849
  throw new Error(
@@ -22363,7 +23879,7 @@ ${lines.join("\n")}`;
22363
23879
  }
22364
23880
  return compile2(body);
22365
23881
  }
22366
- var GPU_GAMMA_PREAMBLE = `
23882
+ var GPU_GAMMA_PREAMBLE_GLSL = `
22367
23883
  float _gpu_gamma(float z) {
22368
23884
  const float PI = 3.14159265358979;
22369
23885
  // For z < 0.5, use reflection formula with inlined Lanczos (non-recursive)
@@ -22395,7 +23911,37 @@ float _gpu_gammaln(float z) {
22395
23911
  + 1.0 / (1260.0 * z3 * z * z);
22396
23912
  }
22397
23913
  `;
22398
- var GPU_ERF_PREAMBLE = `
23914
+ var GPU_GAMMA_PREAMBLE_WGSL = `
23915
+ fn _gpu_gamma(z: f32) -> f32 {
23916
+ let PI = 3.14159265358979;
23917
+ var w = z;
23918
+ if (z < 0.5) { w = 1.0 - z; }
23919
+ w = w - 1.0;
23920
+ var x = 0.99999999999980993;
23921
+ x = x + 676.5203681218851 / (w + 1.0);
23922
+ x = x + -1259.1392167224028 / (w + 2.0);
23923
+ x = x + 771.32342877765313 / (w + 3.0);
23924
+ x = x + -176.61502916214059 / (w + 4.0);
23925
+ x = x + 12.507343278686905 / (w + 5.0);
23926
+ x = x + -0.13857109526572012 / (w + 6.0);
23927
+ x = x + 9.9843695780195716e-6 / (w + 7.0);
23928
+ x = x + 1.5056327351493116e-7 / (w + 8.0);
23929
+ let t = w + 7.5;
23930
+ let g = sqrt(2.0 * PI) * pow(t, w + 0.5) * exp(-t) * x;
23931
+ if (z < 0.5) { return PI / (sin(PI * z) * g); }
23932
+ return g;
23933
+ }
23934
+
23935
+ fn _gpu_gammaln(z: f32) -> f32 {
23936
+ let z3 = z * z * z;
23937
+ return z * log(z) - z - 0.5 * log(z)
23938
+ + 0.5 * log(2.0 * 3.14159265358979)
23939
+ + 1.0 / (12.0 * z)
23940
+ - 1.0 / (360.0 * z3)
23941
+ + 1.0 / (1260.0 * z3 * z * z);
23942
+ }
23943
+ `;
23944
+ var GPU_ERF_PREAMBLE_GLSL = `
22399
23945
  float _gpu_erf(float x) {
22400
23946
  float ax = abs(x);
22401
23947
  float t = 1.0 / (1.0 + 0.3275911 * ax);
@@ -22413,6 +23959,26 @@ float _gpu_erfinv(float x) {
22413
23959
  float x9 = x7 * x2;
22414
23960
  return sqrt(pi) * 0.5 * (x + (pi / 12.0) * x3 + (7.0 * pi * pi / 480.0) * x5 + (127.0 * pi * pi * pi / 40320.0) * x7 + (4369.0 * pi * pi * pi * pi / 5806080.0) * x9);
22415
23961
  }
23962
+ `;
23963
+ var GPU_ERF_PREAMBLE_WGSL = `
23964
+ fn _gpu_erf(x: f32) -> f32 {
23965
+ let ax = abs(x);
23966
+ let t = 1.0 / (1.0 + 0.3275911 * ax);
23967
+ let y = ((((1.061405429 * t - 1.453152027) * t + 1.421413741) * t - 0.284496736) * t + 0.254829592) * t;
23968
+ let result = 1.0 - y * exp(-ax * ax);
23969
+ if (x < 0.0) { return -result; }
23970
+ return result;
23971
+ }
23972
+
23973
+ fn _gpu_erfinv(x: f32) -> f32 {
23974
+ let pi = 3.14159265358979;
23975
+ let x2 = x * x;
23976
+ let x3 = x * x2;
23977
+ let x5 = x3 * x2;
23978
+ let x7 = x5 * x2;
23979
+ let x9 = x7 * x2;
23980
+ return sqrt(pi) * 0.5 * (x + (pi / 12.0) * x3 + (7.0 * pi * pi / 480.0) * x5 + (127.0 * pi * pi * pi / 40320.0) * x7 + (4369.0 * pi * pi * pi * pi / 5806080.0) * x9);
23981
+ }
22416
23982
  `;
22417
23983
  var GPU_HEAVISIDE_PREAMBLE_GLSL = `
22418
23984
  float _gpu_heaviside(float x) {
@@ -22926,6 +24492,212 @@ fn _fractal_julia(z_in: vec2f, c: vec2f, maxIter: i32) -> f32 {
22926
24492
  }
22927
24493
  return 1.0;
22928
24494
  }
24495
+ `;
24496
+ var GPU_GCD_PREAMBLE_GLSL = `
24497
+ float _gpu_gcd(float a, float b) {
24498
+ a = abs(a); b = abs(b);
24499
+ for (int i = 0; i < 32; i++) {
24500
+ if (b < 0.5) break;
24501
+ float t = mod(a, b);
24502
+ a = b;
24503
+ b = t;
24504
+ }
24505
+ return a;
24506
+ }
24507
+ `;
24508
+ var GPU_GCD_PREAMBLE_WGSL = `
24509
+ fn _gpu_gcd(a_in: f32, b_in: f32) -> f32 {
24510
+ var a = abs(a_in); var b = abs(b_in);
24511
+ for (var i: i32 = 0; i < 32; i++) {
24512
+ if (b < 0.5) { break; }
24513
+ let t = a % b;
24514
+ a = b;
24515
+ b = t;
24516
+ }
24517
+ return a;
24518
+ }
24519
+ `;
24520
+ var GPU_RANDOM_PREAMBLE_GLSL = `
24521
+ // Deterministic pseudorandom in [0, 1) from a float seed.
24522
+ // Standard fract-sin hash; reproducible across runs for the same seed.
24523
+ // Note: this hash exhibits visible banding near seed \u2248 k\u03C0 for integer k.
24524
+ // For high-quality shader random, callers should use a more robust hash
24525
+ // (e.g. PCG or xxHash) and pre-seed it appropriately.
24526
+ float _gpu_random(float seed) {
24527
+ return fract(sin(seed * 12.9898) * 43758.5453);
24528
+ }
24529
+ `;
24530
+ var GPU_RANDOM_PREAMBLE_WGSL = `
24531
+ // Deterministic pseudorandom in [0, 1) from a float seed.
24532
+ // Standard fract-sin hash; reproducible across runs for the same seed.
24533
+ // Note: this hash exhibits visible banding near seed \u2248 k\u03C0 for integer k.
24534
+ // For high-quality shader random, callers should use a more robust hash
24535
+ // (e.g. PCG or xxHash) and pre-seed it appropriately.
24536
+ fn _gpu_random(seed: f32) -> f32 {
24537
+ return fract(sin(seed * 12.9898) * 43758.5453);
24538
+ }
24539
+ `;
24540
+ var GPU_MEDIAN_PREAMBLE_GLSL = `
24541
+ float _gpu_median_2(float a, float b) {
24542
+ return (a + b) * 0.5;
24543
+ }
24544
+ float _gpu_median_3(float a, float b, float c) {
24545
+ return max(min(a, b), min(max(a, b), c));
24546
+ }
24547
+ float _gpu_median_4(float a, float b, float c, float d) {
24548
+ float lo = max(min(a, b), min(c, d));
24549
+ float hi = min(max(a, b), max(c, d));
24550
+ return (lo + hi) * 0.5;
24551
+ }
24552
+ float _gpu_median_5(float a, float b, float c, float d, float e) {
24553
+ // 9-comparator Bose-Nelson sort; v2 holds the median.
24554
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e;
24555
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
24556
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24557
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
24558
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
24559
+ t=min(v0,v3); v3=max(v0,v3); v0=t;
24560
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
24561
+ t=min(v1,v4); v4=max(v1,v4); v1=t;
24562
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
24563
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
24564
+ return v2;
24565
+ }
24566
+ float _gpu_median_6(float a, float b, float c, float d, float e, float f) {
24567
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f;
24568
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
24569
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
24570
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
24571
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
24572
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
24573
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
24574
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
24575
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
24576
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
24577
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
24578
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24579
+ return (v2 + v3) * 0.5;
24580
+ }
24581
+ float _gpu_median_7(float a, float b, float c, float d, float e, float f, float g) {
24582
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f,v6=g;
24583
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
24584
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
24585
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
24586
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
24587
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
24588
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
24589
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
24590
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
24591
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
24592
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
24593
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
24594
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
24595
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24596
+ return v3;
24597
+ }
24598
+ float _gpu_median_8(float a, float b, float c, float d, float e, float f, float g, float h) {
24599
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f,v6=g,v7=h;
24600
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
24601
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
24602
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
24603
+ t=min(v6,v7); v7=max(v6,v7); v6=t;
24604
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
24605
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
24606
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
24607
+ t=min(v5,v7); v7=max(v5,v7); v5=t;
24608
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
24609
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
24610
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
24611
+ t=min(v3,v7); v7=max(v3,v7); v3=t;
24612
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
24613
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24614
+ t=min(v5,v6); v6=max(v5,v6); v5=t;
24615
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
24616
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
24617
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24618
+ return (v3 + v4) * 0.5;
24619
+ }
24620
+ `;
24621
+ var GPU_MEDIAN_PREAMBLE_WGSL = `
24622
+ fn _gpu_median_2(a: f32, b: f32) -> f32 {
24623
+ return (a + b) * 0.5;
24624
+ }
24625
+ fn _gpu_median_3(a: f32, b: f32, c: f32) -> f32 {
24626
+ return max(min(a, b), min(max(a, b), c));
24627
+ }
24628
+ fn _gpu_median_4(a: f32, b: f32, c: f32, d: f32) -> f32 {
24629
+ let lo = max(min(a, b), min(c, d));
24630
+ let hi = min(max(a, b), max(c, d));
24631
+ return (lo + hi) * 0.5;
24632
+ }
24633
+ fn _gpu_median_5(a: f32, b: f32, c: f32, d: f32, e: f32) -> f32 {
24634
+ // 9-comparator Bose-Nelson sort; v2 holds the median.
24635
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var t: f32;
24636
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
24637
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24638
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
24639
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
24640
+ t=min(v0,v3); v3=max(v0,v3); v0=t;
24641
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
24642
+ t=min(v1,v4); v4=max(v1,v4); v1=t;
24643
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
24644
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
24645
+ return v2;
24646
+ }
24647
+ fn _gpu_median_6(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) -> f32 {
24648
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var v5=f; var t: f32;
24649
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
24650
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
24651
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
24652
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
24653
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
24654
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
24655
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
24656
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
24657
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
24658
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
24659
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24660
+ return (v2 + v3) * 0.5;
24661
+ }
24662
+ fn _gpu_median_7(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32, g: f32) -> f32 {
24663
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var v5=f; var v6=g; var t: f32;
24664
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
24665
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
24666
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
24667
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
24668
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
24669
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
24670
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
24671
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
24672
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
24673
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
24674
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
24675
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
24676
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24677
+ return v3;
24678
+ }
24679
+ fn _gpu_median_8(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32, g: f32, h: f32) -> f32 {
24680
+ 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;
24681
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
24682
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
24683
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
24684
+ t=min(v6,v7); v7=max(v6,v7); v6=t;
24685
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
24686
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
24687
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
24688
+ t=min(v5,v7); v7=max(v5,v7); v5=t;
24689
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
24690
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
24691
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
24692
+ t=min(v3,v7); v7=max(v3,v7); v3=t;
24693
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
24694
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24695
+ t=min(v5,v6); v6=max(v5,v6); v5=t;
24696
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
24697
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
24698
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24699
+ return (v3 + v4) * 0.5;
24700
+ }
22929
24701
  `;
22930
24702
  var GPU_COLOR_PREAMBLE_GLSL = `
22931
24703
  float _gpu_srgb_to_linear(float c) {
@@ -23587,8 +25359,10 @@ fn _gpu_apca(lch_bg: vec3f, lch_fg: vec3f) -> f32 {
23587
25359
  };
23588
25360
  let preamble = "";
23589
25361
  preamble += buildComplexPreamble(code, this.languageId);
23590
- if (code.includes("_gpu_gamma")) preamble += GPU_GAMMA_PREAMBLE;
23591
- if (code.includes("_gpu_erf")) preamble += GPU_ERF_PREAMBLE;
25362
+ if (code.includes("_gpu_gamma"))
25363
+ preamble += this.languageId === "wgsl" ? GPU_GAMMA_PREAMBLE_WGSL : GPU_GAMMA_PREAMBLE_GLSL;
25364
+ if (code.includes("_gpu_erf"))
25365
+ preamble += this.languageId === "wgsl" ? GPU_ERF_PREAMBLE_WGSL : GPU_ERF_PREAMBLE_GLSL;
23592
25366
  if (code.includes("_gpu_heaviside"))
23593
25367
  preamble += this.languageId === "wgsl" ? GPU_HEAVISIDE_PREAMBLE_WGSL : GPU_HEAVISIDE_PREAMBLE_GLSL;
23594
25368
  if (code.includes("_gpu_sinc"))
@@ -23604,6 +25378,12 @@ fn _gpu_apca(lch_bg: vec3f, lch_fg: vec3f) -> f32 {
23604
25378
  if (code.includes("_fractal_")) {
23605
25379
  preamble += this.languageId === "wgsl" ? GPU_FRACTAL_PREAMBLE_WGSL : GPU_FRACTAL_PREAMBLE_GLSL;
23606
25380
  }
25381
+ if (code.includes("_gpu_random"))
25382
+ preamble += this.languageId === "wgsl" ? GPU_RANDOM_PREAMBLE_WGSL : GPU_RANDOM_PREAMBLE_GLSL;
25383
+ if (code.includes("_gpu_gcd"))
25384
+ preamble += this.languageId === "wgsl" ? GPU_GCD_PREAMBLE_WGSL : GPU_GCD_PREAMBLE_GLSL;
25385
+ if (code.includes("_gpu_median_"))
25386
+ preamble += this.languageId === "wgsl" ? GPU_MEDIAN_PREAMBLE_WGSL : GPU_MEDIAN_PREAMBLE_GLSL;
23607
25387
  if (code.includes("_gpu_srgb_to") || code.includes("_gpu_oklab") || code.includes("_gpu_oklch") || code.includes("_gpu_color_mix") || code.includes("_gpu_apca")) {
23608
25388
  preamble += this.languageId === "wgsl" ? GPU_COLOR_PREAMBLE_WGSL : GPU_COLOR_PREAMBLE_GLSL;
23609
25389
  }
@@ -24368,9 +26148,18 @@ ${code}`;
24368
26148
  return ok({ lo: -xVal.hi, hi: -xVal.lo });
24369
26149
  }
24370
26150
  function _mul(a, b) {
24371
- const products = [a.lo * b.lo, a.lo * b.hi, a.hi * b.lo, a.hi * b.hi];
26151
+ const products = [
26152
+ _prod(a.lo, b.lo),
26153
+ _prod(a.lo, b.hi),
26154
+ _prod(a.hi, b.lo),
26155
+ _prod(a.hi, b.hi)
26156
+ ];
24372
26157
  return { lo: Math.min(...products), hi: Math.max(...products) };
24373
26158
  }
26159
+ function _prod(x, y) {
26160
+ if (x === 0 || y === 0) return 0;
26161
+ return x * y;
26162
+ }
24374
26163
  function mul3(a, b) {
24375
26164
  const unwrapped = unwrapOrPropagate(a, b);
24376
26165
  if (!Array.isArray(unwrapped)) return unwrapped;
@@ -24704,6 +26493,7 @@ ${code}`;
24704
26493
  const period = Math.abs(
24705
26494
  bVal.lo === bVal.hi ? bVal.lo : Math.max(Math.abs(bVal.lo), Math.abs(bVal.hi))
24706
26495
  );
26496
+ const divisorNegative = bVal.hi < 0;
24707
26497
  const flo = Math.floor(aVal.lo / period);
24708
26498
  const fhi = Math.floor(aVal.hi / period);
24709
26499
  if (flo !== fhi) {
@@ -24711,6 +26501,11 @@ ${code}`;
24711
26501
  }
24712
26502
  const modLo = aVal.lo - period * flo;
24713
26503
  const modHi = aVal.hi - period * flo;
26504
+ if (divisorNegative) {
26505
+ if (modLo === 0)
26506
+ return { kind: "singular", at: aVal.lo, continuity: "right" };
26507
+ return ok({ lo: modLo - period, hi: modHi - period });
26508
+ }
24714
26509
  return ok({ lo: Math.min(modLo, modHi), hi: Math.max(modLo, modHi) });
24715
26510
  }
24716
26511
  function remainder(a, b) {
@@ -24742,6 +26537,23 @@ ${code}`;
24742
26537
  const [xVal] = unwrapped;
24743
26538
  return _gamma(xVal);
24744
26539
  }
26540
+ var GAMMA_NEG_EXTREMA_X = [
26541
+ -0.504083008264455,
26542
+ -1.573498473162391,
26543
+ -2.610720868444145,
26544
+ -3.635293366436901,
26545
+ -4.653163765628266,
26546
+ -5.667162441556885,
26547
+ -6.678418213073426,
26548
+ -7.687788325031709,
26549
+ -8.695764163640956,
26550
+ -9.702672540001863
26551
+ ];
26552
+ function gammaNegStripExtremum(lo) {
26553
+ const n = Math.floor(lo);
26554
+ const idx = -n - 1;
26555
+ return idx >= 0 && idx < GAMMA_NEG_EXTREMA_X.length ? GAMMA_NEG_EXTREMA_X[idx] : null;
26556
+ }
24745
26557
  function _gamma(x) {
24746
26558
  if (x.hi >= 0 && x.lo <= 0) {
24747
26559
  return { kind: "singular", at: 0 };
@@ -24754,7 +26566,21 @@ ${code}`;
24754
26566
  }
24755
26567
  const gLo = gamma(x.lo);
24756
26568
  const gHi = gamma(x.hi);
24757
- return ok({ lo: Math.min(gLo, gHi), hi: Math.max(gLo, gHi) });
26569
+ let lo = Math.min(gLo, gHi);
26570
+ let hi = Math.max(gLo, gHi);
26571
+ const xStar = gammaNegStripExtremum(x.lo);
26572
+ if (xStar !== null) {
26573
+ if (xStar >= x.lo && xStar <= x.hi) {
26574
+ const g = gamma(xStar);
26575
+ lo = Math.min(lo, g);
26576
+ hi = Math.max(hi, g);
26577
+ }
26578
+ } else {
26579
+ const stripEven = Math.floor(x.lo) % 2 === 0;
26580
+ if (stripEven) lo = Math.min(lo, 0);
26581
+ else hi = Math.max(hi, 0);
26582
+ }
26583
+ return ok({ lo, hi });
24758
26584
  }
24759
26585
  if (x.lo >= GAMMA_MIN_X) {
24760
26586
  return ok({ lo: gamma(x.lo), hi: gamma(x.hi) });
@@ -24785,7 +26611,15 @@ ${code}`;
24785
26611
  }
24786
26612
  const gLo = gammaln(x.lo);
24787
26613
  const gHi = gammaln(x.hi);
24788
- return ok({ lo: Math.min(gLo, gHi), hi: Math.max(gLo, gHi) });
26614
+ let lo = Math.min(gLo, gHi);
26615
+ const hi = Math.max(gLo, gHi);
26616
+ const xStar = gammaNegStripExtremum(x.lo);
26617
+ if (xStar !== null) {
26618
+ if (xStar >= x.lo && xStar <= x.hi) lo = Math.min(lo, gammaln(xStar));
26619
+ } else {
26620
+ lo = -Infinity;
26621
+ }
26622
+ return ok({ lo, hi });
24789
26623
  }
24790
26624
  return ok({ lo: gammaln(x.lo), hi: gammaln(x.hi) });
24791
26625
  }
@@ -24811,6 +26645,33 @@ ${code}`;
24811
26645
  return ok({ lo: Math.min(fLo, fHi), hi: Math.max(fLo, fHi) });
24812
26646
  return ok({ lo: fLo, hi: fHi });
24813
26647
  }
26648
+ var MAX_INT_ENUM_POINTS = 4096;
26649
+ function integerPoints(lo, hi, cap) {
26650
+ const a = Math.round(lo);
26651
+ const b = Math.round(hi);
26652
+ if (!Number.isFinite(a) || !Number.isFinite(b)) return null;
26653
+ if (b - a + 1 > cap) return null;
26654
+ const out = [];
26655
+ for (let i = a; i <= b; i++) out.push(i);
26656
+ return out;
26657
+ }
26658
+ function enumerateInteger2(a, b, f) {
26659
+ const xs = integerPoints(a.lo, a.hi, MAX_INT_ENUM_POINTS);
26660
+ const ys = integerPoints(b.lo, b.hi, MAX_INT_ENUM_POINTS);
26661
+ if (!xs || !ys || xs.length * ys.length > MAX_INT_ENUM_POINTS) return null;
26662
+ let lo = Infinity;
26663
+ let hi = -Infinity;
26664
+ for (const x of xs)
26665
+ for (const y of ys) {
26666
+ const v = f(x, y);
26667
+ if (Number.isFinite(v)) {
26668
+ if (v < lo) lo = v;
26669
+ if (v > hi) hi = v;
26670
+ }
26671
+ }
26672
+ if (lo === Infinity) return null;
26673
+ return ok({ lo, hi });
26674
+ }
24814
26675
  function binomial(n, k) {
24815
26676
  const uN = unwrapOrPropagate(n);
24816
26677
  if (!Array.isArray(uN)) return uN;
@@ -24818,13 +26679,10 @@ ${code}`;
24818
26679
  if (!Array.isArray(uK)) return uK;
24819
26680
  const [nVal] = uN;
24820
26681
  const [kVal] = uK;
24821
- const vals = [
24822
- choose(Math.round(nVal.lo), Math.round(kVal.lo)),
24823
- choose(Math.round(nVal.lo), Math.round(kVal.hi)),
24824
- choose(Math.round(nVal.hi), Math.round(kVal.lo)),
24825
- choose(Math.round(nVal.hi), Math.round(kVal.hi))
24826
- ];
24827
- return ok({ lo: Math.min(...vals), hi: Math.max(...vals) });
26682
+ const enumerated = enumerateInteger2(nVal, kVal, choose);
26683
+ if (enumerated) return enumerated;
26684
+ const nMax = Math.round(nVal.hi);
26685
+ return ok({ lo: 0, hi: choose(nMax, Math.floor(nMax / 2)) });
24828
26686
  }
24829
26687
  function gcd3(a, b) {
24830
26688
  const uA = unwrapOrPropagate(a);
@@ -24833,13 +26691,15 @@ ${code}`;
24833
26691
  if (!Array.isArray(uB)) return uB;
24834
26692
  const [aVal] = uA;
24835
26693
  const [bVal] = uB;
24836
- const vals = [
24837
- gcd(Math.round(aVal.lo), Math.round(bVal.lo)),
24838
- gcd(Math.round(aVal.lo), Math.round(bVal.hi)),
24839
- gcd(Math.round(aVal.hi), Math.round(bVal.lo)),
24840
- gcd(Math.round(aVal.hi), Math.round(bVal.hi))
24841
- ];
24842
- return ok({ lo: Math.min(...vals), hi: Math.max(...vals) });
26694
+ const enumerated = enumerateInteger2(aVal, bVal, gcd);
26695
+ if (enumerated) return enumerated;
26696
+ const m = Math.max(
26697
+ Math.abs(Math.round(aVal.lo)),
26698
+ Math.abs(Math.round(aVal.hi)),
26699
+ Math.abs(Math.round(bVal.lo)),
26700
+ Math.abs(Math.round(bVal.hi))
26701
+ );
26702
+ return ok({ lo: 0, hi: m });
24843
26703
  }
24844
26704
  function lcm3(a, b) {
24845
26705
  const uA = unwrapOrPropagate(a);
@@ -24848,13 +26708,11 @@ ${code}`;
24848
26708
  if (!Array.isArray(uB)) return uB;
24849
26709
  const [aVal] = uA;
24850
26710
  const [bVal] = uB;
24851
- const vals = [
24852
- lcm(Math.round(aVal.lo), Math.round(bVal.lo)),
24853
- lcm(Math.round(aVal.lo), Math.round(bVal.hi)),
24854
- lcm(Math.round(aVal.hi), Math.round(bVal.lo)),
24855
- lcm(Math.round(aVal.hi), Math.round(bVal.hi))
24856
- ];
24857
- return ok({ lo: Math.min(...vals), hi: Math.max(...vals) });
26711
+ const enumerated = enumerateInteger2(aVal, bVal, lcm);
26712
+ if (enumerated) return enumerated;
26713
+ const ma = Math.max(Math.abs(Math.round(aVal.lo)), Math.abs(Math.round(aVal.hi)));
26714
+ const mb = Math.max(Math.abs(Math.round(bVal.lo)), Math.abs(Math.round(bVal.hi)));
26715
+ return ok({ lo: 0, hi: ma * mb });
24858
26716
  }
24859
26717
  function chop2(x) {
24860
26718
  const unwrapped = unwrapOrPropagate(x);
@@ -25246,7 +27104,6 @@ ${code}`;
25246
27104
  29.8116,
25247
27105
  32.95639
25248
27106
  ];
25249
- var SINC_GLOBAL_LO = -0.21724;
25250
27107
  function sinc2(x) {
25251
27108
  const unwrapped = unwrapOrPropagate(x);
25252
27109
  if (!Array.isArray(unwrapped)) return unwrapped;
@@ -25267,8 +27124,14 @@ ${code}`;
25267
27124
  if (e >= xVal.lo && e <= xVal.hi) update(sincVal(e));
25268
27125
  if (-e >= xVal.lo && -e <= xVal.hi) update(sincVal(-e));
25269
27126
  }
25270
- if (Math.abs(xVal.lo) > lastExtremum || Math.abs(xVal.hi) > lastExtremum) {
25271
- update(SINC_GLOBAL_LO);
27127
+ let minBeyondAbs = Infinity;
27128
+ if (xVal.hi > lastExtremum)
27129
+ minBeyondAbs = Math.min(minBeyondAbs, Math.max(xVal.lo, lastExtremum));
27130
+ if (xVal.lo < -lastExtremum)
27131
+ minBeyondAbs = Math.min(minBeyondAbs, -Math.min(xVal.hi, -lastExtremum));
27132
+ if (Number.isFinite(minBeyondAbs) && minBeyondAbs > 0) {
27133
+ update(1 / minBeyondAbs);
27134
+ update(-1 / minBeyondAbs);
25272
27135
  }
25273
27136
  return ok({ lo, hi });
25274
27137
  }
@@ -25294,8 +27157,21 @@ ${code}`;
25294
27157
  if (e >= xVal.lo && e <= xVal.hi) update(fresnelS(e));
25295
27158
  if (-e >= xVal.lo && -e <= xVal.hi) update(fresnelS(-e));
25296
27159
  }
27160
+ fresnelConvergenceBound(xVal, FRESNEL_S_EXTREMA, fresnelS, update);
25297
27161
  return ok({ lo, hi });
25298
27162
  }
27163
+ function fresnelConvergenceBound(xVal, extrema, scalar, update) {
27164
+ const lastE = extrema[extrema.length - 1];
27165
+ const amp = Math.abs(scalar(lastE) - 0.5);
27166
+ if (xVal.hi > lastE) {
27167
+ update(0.5 + amp);
27168
+ update(0.5 - amp);
27169
+ }
27170
+ if (xVal.lo < -lastE) {
27171
+ update(-0.5 - amp);
27172
+ update(-0.5 + amp);
27173
+ }
27174
+ }
25299
27175
  function fresnelC2(x) {
25300
27176
  const unwrapped = unwrapOrPropagate(x);
25301
27177
  if (!Array.isArray(unwrapped)) return unwrapped;
@@ -25312,6 +27188,7 @@ ${code}`;
25312
27188
  if (e >= xVal.lo && e <= xVal.hi) update(fresnelC(e));
25313
27189
  if (-e >= xVal.lo && -e <= xVal.hi) update(fresnelC(-e));
25314
27190
  }
27191
+ fresnelConvergenceBound(xVal, FRESNEL_C_EXTREMA, fresnelC, update);
25315
27192
  return ok({ lo, hi });
25316
27193
  }
25317
27194
 
@@ -25419,11 +27296,9 @@ ${code}`;
25419
27296
  const unwrapped = unwrapOrPropagate(x, lo, hi);
25420
27297
  if (!Array.isArray(unwrapped)) return unwrapped;
25421
27298
  const [xVal, loVal, hiVal] = unwrapped;
25422
- const resultLo = Math.max(xVal.lo, loVal.lo);
25423
- const resultHi = Math.min(xVal.hi, hiVal.hi);
25424
- if (resultLo > resultHi) {
25425
- return { kind: "empty" };
25426
- }
27299
+ const lowered = { lo: Math.max(xVal.lo, loVal.lo), hi: Math.max(xVal.hi, loVal.hi) };
27300
+ const resultLo = Math.min(lowered.lo, hiVal.lo);
27301
+ const resultHi = Math.min(lowered.hi, hiVal.hi);
25427
27302
  return { kind: "interval", value: { lo: resultLo, hi: resultHi } };
25428
27303
  }
25429
27304
 
@@ -25756,7 +27631,7 @@ ${code}`;
25756
27631
  function compileIntervalBound(expr, numVal, target) {
25757
27632
  if (numVal !== void 0) return String(numVal);
25758
27633
  const compiled = BaseCompiler.compile(expr, target);
25759
- return `Math.floor((${compiled}).hi)`;
27634
+ return `Math.floor(((_b) => (_b && _b.value ? _b.value.hi : _b.hi))(${compiled}))`;
25760
27635
  }
25761
27636
  function compileIntervalSumProduct(kind, args, _compile, target) {
25762
27637
  if (!args[0]) throw new Error(`${kind}: no body`);
@@ -25942,7 +27817,7 @@ ${code}`;
25942
27817
  }
25943
27818
 
25944
27819
  // src/compile.ts
25945
- var version = "0.57.0";
27820
+ var version = "0.59.0";
25946
27821
  return __toCommonJS(compile_exports);
25947
27822
  })();
25948
27823
  /*! Bundled license information: