@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
- /** Compute Engine 0.57.0 */
1
+ /** Compute Engine 0.59.0 */
2
2
 
3
3
  // src/compute-engine/numerics/richardson.ts
4
4
  function extrapolate(f, x0, options = {}) {
@@ -159,6 +159,7 @@ function fpexp(x, scale) {
159
159
  return sum;
160
160
  }
161
161
  function fpln(x, scale) {
162
+ if (x <= 0n) throw new RangeError("fpln: input must be positive");
162
163
  if (x === scale) return 0n;
163
164
  const xNum = Number(x);
164
165
  const scaleNum = Number(scale);
@@ -808,9 +809,11 @@ var BigDecimal = class _BigDecimal {
808
809
  if (Number.isFinite(thisExp) && Number.isFinite(otherExp)) {
809
810
  if (other.significand === 0n) return _BigDecimal.NAN;
810
811
  if (this.significand === 0n) return fromRaw(0n, 0);
811
- return this.sub(this.div(other).trunc().mul(other)).toPrecision(
812
- _BigDecimal.precision
813
- );
812
+ const ediff = thisExp - otherExp;
813
+ const num = ediff >= 0 ? this.significand * pow10(ediff) : this.significand;
814
+ const den = ediff >= 0 ? other.significand : other.significand * pow10(-ediff);
815
+ const q = num / den;
816
+ return this.sub(fromRaw(q, 0).mul(other));
814
817
  }
815
818
  if (thisExp !== thisExp || otherExp !== otherExp) return _BigDecimal.NAN;
816
819
  if (!Number.isFinite(thisExp)) return _BigDecimal.NAN;
@@ -855,7 +858,10 @@ var BigDecimal = class _BigDecimal {
855
858
  return this.pow(n.neg()).inv();
856
859
  }
857
860
  const absSig = this.significand < 0n ? -this.significand : this.significand;
858
- const thisLog10 = bigintDigits(absSig) + this.exponent;
861
+ const sigDigits = bigintDigits(absSig);
862
+ const dropped = sigDigits > 15 ? sigDigits - 15 : 0;
863
+ const lead = dropped > 0 ? Number(absSig / 10n ** BigInt(dropped)) : Number(absSig);
864
+ const thisLog10 = Math.log10(lead) + dropped + this.exponent;
859
865
  const resultLog10 = Number(expValue) * thisLog10;
860
866
  if (resultLog10 > 9e15) {
861
867
  return this.significand < 0n && expValue % 2n !== 0n ? _BigDecimal.NEGATIVE_INFINITY : _BigDecimal.POSITIVE_INFINITY;
@@ -888,7 +894,19 @@ var BigDecimal = class _BigDecimal {
888
894
  return _BigDecimal.POSITIVE_INFINITY;
889
895
  }
890
896
  if (this.significand < 0n) return _BigDecimal.NAN;
891
- return n.mul(this.ln()).exp();
897
+ const baseSig = this.significand;
898
+ const decExpBase = this.exponent + bigintDigits(baseSig) - 1;
899
+ const nSig = n.significand < 0n ? -n.significand : n.significand;
900
+ const decExpN = n.exponent + bigintDigits(nSig) - 1;
901
+ const argMag = decExpN + Math.log10(Math.abs(decExpBase) * 2.303 + 3) + 1;
902
+ const extra = Math.min(20, Math.max(2, Math.ceil(argMag) + 2));
903
+ const savedPrec = _BigDecimal.precision;
904
+ _BigDecimal.precision = savedPrec + extra;
905
+ try {
906
+ return n.mul(this.ln()).exp().toPrecision(savedPrec);
907
+ } finally {
908
+ _BigDecimal.precision = savedPrec;
909
+ }
892
910
  }
893
911
  // ---------- Conversion methods ----------
894
912
  /** Convert to a JavaScript number. May lose precision for large values. */
@@ -1129,6 +1147,20 @@ function fromFixedPoint(fp, scale, targetPrecision) {
1129
1147
  const sig = negative ? -absFp : absFp;
1130
1148
  return fromRaw(sig, resultExp);
1131
1149
  }
1150
+ function decimalExponent(x) {
1151
+ const sig = x.significand < 0n ? -x.significand : x.significand;
1152
+ return x.exponent + bigintDigits(sig) - 1;
1153
+ }
1154
+ var MAX_SAFE_EXPONENT = BigInt(Number.MAX_SAFE_INTEGER);
1155
+ var _ln10Fp = null;
1156
+ var _ln10Scale = null;
1157
+ function ln10Fixed(scale) {
1158
+ if (_ln10Scale !== scale) {
1159
+ _ln10Fp = fpln(10n * scale, scale);
1160
+ _ln10Scale = scale;
1161
+ }
1162
+ return _ln10Fp;
1163
+ }
1132
1164
  BigDecimal.prototype.sqrt = function() {
1133
1165
  if (this.isNaN()) return BigDecimal.NAN;
1134
1166
  if (this.isZero()) return BigDecimal.ZERO;
@@ -1139,9 +1171,13 @@ BigDecimal.prototype.sqrt = function() {
1139
1171
  if (this.significand < 0n) return BigDecimal.NAN;
1140
1172
  const targetPrec = BigDecimal.precision;
1141
1173
  const workingPrec = targetPrec + 10;
1142
- const [fp, scale] = toFixedPoint(this, workingPrec);
1174
+ const e = decimalExponent(this);
1175
+ const k = Math.floor(e / 2);
1176
+ const m = fromRaw(this.significand, this.exponent - 2 * k);
1177
+ const [fp, scale] = toFixedPoint(m, workingPrec);
1143
1178
  const sqrtFp = fpsqrt(fp, scale);
1144
- return fromFixedPoint(sqrtFp, scale, targetPrec);
1179
+ const root = fromFixedPoint(sqrtFp, scale, targetPrec);
1180
+ return fromRaw(root.significand, root.exponent + k);
1145
1181
  };
1146
1182
  BigDecimal.prototype.cbrt = function() {
1147
1183
  if (this.isNaN()) return BigDecimal.NAN;
@@ -1155,10 +1191,13 @@ BigDecimal.prototype.cbrt = function() {
1155
1191
  }
1156
1192
  const targetPrec = BigDecimal.precision;
1157
1193
  const workingPrec = targetPrec + 10;
1158
- const [fp, scale] = toFixedPoint(this, workingPrec);
1194
+ const e = decimalExponent(this);
1195
+ const k = Math.floor(e / 3);
1196
+ const m = fromRaw(this.significand, this.exponent - 3 * k);
1197
+ const [fp, scale] = toFixedPoint(m, workingPrec);
1159
1198
  const C = fp * scale * scale;
1160
1199
  let x;
1161
- const numVal = this.toNumber();
1200
+ const numVal = m.toNumber();
1162
1201
  const scaleNum = Number(scale);
1163
1202
  if (Number.isFinite(numVal) && numVal > 0 && Number.isFinite(scaleNum)) {
1164
1203
  const approx = Math.cbrt(numVal);
@@ -1187,7 +1226,8 @@ BigDecimal.prototype.cbrt = function() {
1187
1226
  const diffNext = bigintAbs(next * next * next - C);
1188
1227
  if (diffNext < diffX) x = next;
1189
1228
  }
1190
- return fromFixedPoint(x, scale, targetPrec);
1229
+ const root = fromFixedPoint(x, scale, targetPrec);
1230
+ return fromRaw(root.significand, root.exponent + k);
1191
1231
  };
1192
1232
  BigDecimal.sqrt = function(x) {
1193
1233
  return x.sqrt();
@@ -1202,11 +1242,27 @@ BigDecimal.prototype.exp = function() {
1202
1242
  return BigDecimal.ZERO;
1203
1243
  }
1204
1244
  if (this.isZero()) return BigDecimal.ONE;
1245
+ if (decimalExponent(this) >= 17)
1246
+ return this.significand > 0n ? BigDecimal.POSITIVE_INFINITY : BigDecimal.ZERO;
1205
1247
  const targetPrec = BigDecimal.precision;
1206
- const workingPrec = targetPrec + 15;
1207
- const [fp, scale] = toFixedPoint(this, workingPrec);
1208
- const expFp = fpexp(fp, scale);
1209
- return fromFixedPoint(expFp, scale, targetPrec);
1248
+ const absSig = this.significand < 0n ? -this.significand : this.significand;
1249
+ const magnitude = Math.max(0, this.exponent + bigintDigits(absSig));
1250
+ const workingPrec = targetPrec + 20 + magnitude;
1251
+ const [xFp, scale] = toFixedPoint(this, workingPrec);
1252
+ const l10 = ln10Fixed(scale);
1253
+ let k = xFp / l10;
1254
+ let rFp = xFp - k * l10;
1255
+ if (rFp < 0n) {
1256
+ k -= 1n;
1257
+ rFp += l10;
1258
+ }
1259
+ if (k > MAX_SAFE_EXPONENT || k < -MAX_SAFE_EXPONENT)
1260
+ return k > 0n ? BigDecimal.POSITIVE_INFINITY : BigDecimal.ZERO;
1261
+ const expR = fromFixedPoint(fpexp(rFp, scale), scale, targetPrec);
1262
+ const newExp = expR.exponent + Number(k);
1263
+ if (!Number.isSafeInteger(newExp))
1264
+ return k > 0n ? BigDecimal.POSITIVE_INFINITY : BigDecimal.ZERO;
1265
+ return fromRaw(expR.significand, newExp);
1210
1266
  };
1211
1267
  BigDecimal.prototype.ln = function() {
1212
1268
  if (this.isNaN()) return BigDecimal.NAN;
@@ -1218,10 +1274,16 @@ BigDecimal.prototype.ln = function() {
1218
1274
  if (this.significand < 0n) return BigDecimal.NAN;
1219
1275
  if (this.eq(1)) return BigDecimal.ZERO;
1220
1276
  const targetPrec = BigDecimal.precision;
1221
- const workingPrec = targetPrec + 15;
1222
- const [fp, scale] = toFixedPoint(this, workingPrec);
1223
- const lnFp = fpln(fp, scale);
1224
- return fromFixedPoint(lnFp, scale, targetPrec);
1277
+ const sig = this.significand;
1278
+ const digits = bigintDigits(sig);
1279
+ const e = this.exponent + digits - 1;
1280
+ const m = fromRaw(sig, -(digits - 1));
1281
+ const eDigits = Math.abs(e).toString().length;
1282
+ const workingPrec = targetPrec + 20 + eDigits;
1283
+ const [mFp, scale] = toFixedPoint(m, workingPrec);
1284
+ const l10 = ln10Fixed(scale);
1285
+ const resultFp = fpln(mFp, scale) + BigInt(e) * l10;
1286
+ return fromFixedPoint(resultFp, scale, targetPrec);
1225
1287
  };
1226
1288
  BigDecimal.prototype.log = function(base) {
1227
1289
  const b = base instanceof BigDecimal ? base : new BigDecimal(base);
@@ -1241,7 +1303,10 @@ BigDecimal.prototype.sin = function() {
1241
1303
  if (!this.isFinite()) return BigDecimal.NAN;
1242
1304
  if (this.isZero()) return BigDecimal.ZERO;
1243
1305
  const targetPrec = BigDecimal.precision;
1244
- const workingPrec = targetPrec + 15;
1306
+ const e = decimalExponent(this);
1307
+ if (e < 0 && -2 * e >= targetPrec + 4) return this.toPrecision(targetPrec);
1308
+ const workingPrec = targetPrec + 15 + (e < 0 ? -e : 0);
1309
+ if (e > PI_DIGITS.length - workingPrec - 30) return BigDecimal.NAN;
1245
1310
  const [fp, scale] = toFixedPoint(this, workingPrec);
1246
1311
  const [sinFp] = fpsincos(fp, scale);
1247
1312
  return fromFixedPoint(sinFp, scale, targetPrec);
@@ -1252,6 +1317,8 @@ BigDecimal.prototype.cos = function() {
1252
1317
  if (this.isZero()) return BigDecimal.ONE;
1253
1318
  const targetPrec = BigDecimal.precision;
1254
1319
  const workingPrec = targetPrec + 15;
1320
+ const e = decimalExponent(this);
1321
+ if (e > PI_DIGITS.length - workingPrec - 30) return BigDecimal.NAN;
1255
1322
  const [fp, scale] = toFixedPoint(this, workingPrec);
1256
1323
  const [, cosFp] = fpsincos(fp, scale);
1257
1324
  return fromFixedPoint(cosFp, scale, targetPrec);
@@ -1261,7 +1328,10 @@ BigDecimal.prototype.tan = function() {
1261
1328
  if (!this.isFinite()) return BigDecimal.NAN;
1262
1329
  if (this.isZero()) return BigDecimal.ZERO;
1263
1330
  const targetPrec = BigDecimal.precision;
1264
- const workingPrec = targetPrec + 15;
1331
+ const e = decimalExponent(this);
1332
+ if (e < 0 && -2 * e >= targetPrec + 4) return this.toPrecision(targetPrec);
1333
+ const workingPrec = targetPrec + 15 + (e < 0 ? -e : 0);
1334
+ if (e > PI_DIGITS.length - workingPrec - 30) return BigDecimal.NAN;
1265
1335
  const [fp, scale] = toFixedPoint(this, workingPrec);
1266
1336
  const [sinFp, cosFp] = fpsincos(fp, scale);
1267
1337
  if (cosFp === 0n) {
@@ -1279,7 +1349,9 @@ BigDecimal.prototype.atan = function() {
1279
1349
  return piHalf.neg();
1280
1350
  }
1281
1351
  const targetPrec = BigDecimal.precision;
1282
- const workingPrec = targetPrec + 15;
1352
+ const e = decimalExponent(this);
1353
+ if (e < 0 && -2 * e >= targetPrec + 4) return this.toPrecision(targetPrec);
1354
+ const workingPrec = targetPrec + 15 + (e < 0 ? -e : 0);
1283
1355
  const [fp, scale] = toFixedPoint(this, workingPrec);
1284
1356
  const atanFp = fpatan(fp, scale);
1285
1357
  return fromFixedPoint(atanFp, scale, targetPrec);
@@ -1296,7 +1368,9 @@ BigDecimal.prototype.asin = function() {
1296
1368
  return this.significand > 0n ? piHalf : piHalf.neg();
1297
1369
  }
1298
1370
  const targetPrec = BigDecimal.precision;
1299
- const workingPrec = targetPrec + 20;
1371
+ const e = decimalExponent(this);
1372
+ if (e < 0 && -2 * e >= targetPrec + 4) return this.toPrecision(targetPrec);
1373
+ const workingPrec = targetPrec + 20 + (e < 0 ? -e : 0);
1300
1374
  const [xFp, scale] = toFixedPoint(this, workingPrec);
1301
1375
  const x2 = fpmul(xFp, xFp, scale);
1302
1376
  const oneMinusX2 = scale - x2;
@@ -1359,6 +1433,23 @@ BigDecimal.prototype.sinh = function() {
1359
1433
  if (this.significand > 0n) return BigDecimal.POSITIVE_INFINITY;
1360
1434
  return BigDecimal.NEGATIVE_INFINITY;
1361
1435
  }
1436
+ const targetPrec = BigDecimal.precision;
1437
+ const e = decimalExponent(this);
1438
+ if (e < 0) {
1439
+ if (-2 * e >= targetPrec + 4) return this.toPrecision(targetPrec);
1440
+ const saved = BigDecimal.precision;
1441
+ BigDecimal.precision = targetPrec - e + 5;
1442
+ try {
1443
+ const expX2 = this.exp();
1444
+ return expX2.sub(expX2.inv()).div(BigDecimal.TWO).toPrecision(targetPrec);
1445
+ } finally {
1446
+ BigDecimal.precision = saved;
1447
+ }
1448
+ }
1449
+ if (Math.abs(this.toNumber()) > 1.16 * (targetPrec + 3)) {
1450
+ const h = this.abs().exp().div(BigDecimal.TWO);
1451
+ return this.significand > 0n ? h : h.neg();
1452
+ }
1362
1453
  const expX = this.exp();
1363
1454
  const expNegX = expX.inv();
1364
1455
  return expX.sub(expNegX).div(BigDecimal.TWO);
@@ -1369,6 +1460,9 @@ BigDecimal.prototype.cosh = function() {
1369
1460
  if (!this.isFinite()) {
1370
1461
  return BigDecimal.POSITIVE_INFINITY;
1371
1462
  }
1463
+ const targetPrec = BigDecimal.precision;
1464
+ if (Math.abs(this.toNumber()) > 1.16 * (targetPrec + 3))
1465
+ return this.abs().exp().div(BigDecimal.TWO);
1372
1466
  const expX = this.exp();
1373
1467
  const expNegX = expX.inv();
1374
1468
  return expX.add(expNegX).div(BigDecimal.TWO);
@@ -1380,6 +1474,21 @@ BigDecimal.prototype.tanh = function() {
1380
1474
  if (this.significand > 0n) return BigDecimal.ONE;
1381
1475
  return BigDecimal.NEGATIVE_ONE;
1382
1476
  }
1477
+ const targetPrec = BigDecimal.precision;
1478
+ const e = decimalExponent(this);
1479
+ if (e < 0) {
1480
+ if (-2 * e >= targetPrec + 4) return this.toPrecision(targetPrec);
1481
+ const saved = BigDecimal.precision;
1482
+ BigDecimal.precision = targetPrec - e + 5;
1483
+ try {
1484
+ const exp2x2 = this.mul(BigDecimal.TWO).exp();
1485
+ return exp2x2.sub(BigDecimal.ONE).div(exp2x2.add(BigDecimal.ONE)).toPrecision(targetPrec);
1486
+ } finally {
1487
+ BigDecimal.precision = saved;
1488
+ }
1489
+ }
1490
+ if (Math.abs(this.toNumber()) > 1.16 * (targetPrec + 3))
1491
+ return this.significand > 0n ? BigDecimal.ONE : BigDecimal.NEGATIVE_ONE;
1383
1492
  const exp2x = this.mul(BigDecimal.TWO).exp();
1384
1493
  return exp2x.sub(BigDecimal.ONE).div(exp2x.add(BigDecimal.ONE));
1385
1494
  };
@@ -1428,6 +1537,7 @@ var MACHINE_PRECISION = Math.floor(
1428
1537
  Math.log10(Math.pow(2, MACHINE_PRECISION_BITS))
1429
1538
  );
1430
1539
  var DEFAULT_TOLERANCE = 1e-10;
1540
+ var SMALL_INTEGER = 1e6;
1431
1541
  var MAX_ITERATION = 1e4;
1432
1542
  function gcd(a, b) {
1433
1543
  if (a === 0) return b;
@@ -1439,7 +1549,8 @@ function gcd(a, b) {
1439
1549
  }
1440
1550
  function lcm(a, b) {
1441
1551
  if (a === 0 || b === 0) return 0;
1442
- const res = BigInt(a) * BigInt(b) / BigInt(gcd(a, b));
1552
+ let res = BigInt(a) * BigInt(b) / BigInt(gcd(a, b));
1553
+ if (res < 0n) res = -res;
1443
1554
  return Number(res);
1444
1555
  }
1445
1556
  function factorial(n) {
@@ -1529,216 +1640,27 @@ var PRIMITIVE_TYPES = [
1529
1640
  "error",
1530
1641
  ...EXPRESSION_TYPES
1531
1642
  ];
1643
+ var NUMERIC_TYPES_SET = new Set(
1644
+ NUMERIC_TYPES
1645
+ );
1646
+ var COLLECTION_TYPES_SET = new Set(
1647
+ COLLECTION_TYPES
1648
+ );
1649
+ var SCALAR_TYPES_SET = new Set(
1650
+ SCALAR_TYPES
1651
+ );
1652
+ var PRIMITIVE_TYPES_SET = new Set(
1653
+ PRIMITIVE_TYPES
1654
+ );
1655
+ function isValidPrimitiveType(s) {
1656
+ if (typeof s !== "string") return false;
1657
+ return PRIMITIVE_TYPES_SET.has(s);
1658
+ }
1532
1659
  function isValidType(t) {
1533
- if (typeof t === "string")
1534
- return PRIMITIVE_TYPES.includes(t);
1660
+ if (typeof t === "string") return PRIMITIVE_TYPES_SET.has(t);
1535
1661
  if (typeof t !== "object") return false;
1536
1662
  if (!("kind" in t)) return false;
1537
- 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";
1538
- }
1539
-
1540
- // src/common/type/serialize.ts
1541
- var NEGATION_PRECEDENCE = 3;
1542
- var UNION_PRECEDENCE = 1;
1543
- var INTERSECTION_PRECEDENCE = 2;
1544
- var LIST_PRECEDENCE = 4;
1545
- var RECORD_PRECEDENCE = 5;
1546
- var DICTIONARY_PRECEDENCE = 6;
1547
- var SET_PRECEDENCE = 7;
1548
- var COLLECTION_PRECEDENCE = 8;
1549
- var TUPLE_PRECEDENCE = 9;
1550
- var SIGNATURE_PRECEDENCE = 10;
1551
- var VALUE_PRECEDENCE = 11;
1552
- function typeToString(type, precedence = 0) {
1553
- if (typeof type === "string") return type;
1554
- let result = "";
1555
- switch (type.kind) {
1556
- case "value":
1557
- if (typeof type.value === "string") result = `"${type.value}"`;
1558
- else if (typeof type.value === "boolean")
1559
- result = type.value ? "true" : "false";
1560
- else result = type.value.toString();
1561
- break;
1562
- case "reference":
1563
- result = type.name;
1564
- break;
1565
- case "negation":
1566
- result = `!${typeToString(type.type, NEGATION_PRECEDENCE)}`;
1567
- break;
1568
- case "union":
1569
- result = type.types.map((t) => typeToString(t, UNION_PRECEDENCE)).join(" | ");
1570
- break;
1571
- case "intersection":
1572
- result = type.types.map((t) => typeToString(t, INTERSECTION_PRECEDENCE)).join(" & ");
1573
- break;
1574
- case "expression":
1575
- result = `expression<${symbolName(type.operator)}>`;
1576
- break;
1577
- case "symbol":
1578
- result = `symbol<${symbolName(type.name)}>`;
1579
- break;
1580
- case "numeric":
1581
- if (Number.isFinite(type.lower) && Number.isFinite(type.upper)) {
1582
- result = `${type.type}<${type.lower}..${type.upper}>`;
1583
- } else if (Number.isFinite(type.lower)) {
1584
- result = `${type.type}<${type.lower}..>`;
1585
- } else if (Number.isFinite(type.upper)) {
1586
- result = `${type.type}<..${type.upper}>`;
1587
- } else {
1588
- result = `${type.type}`;
1589
- }
1590
- break;
1591
- case "list":
1592
- if (type.dimensions && typeof type.elements === "string" && NUMERIC_TYPES.includes(type.elements)) {
1593
- if (type.dimensions === void 0) {
1594
- if (type.elements === "number") result = "tensor";
1595
- } else if (type.dimensions.length === 1) {
1596
- if (type.elements === "number") {
1597
- if (type.dimensions[0] < 0) result = "vector";
1598
- else result = `vector<${type.dimensions[0]}>`;
1599
- } else {
1600
- if (type.dimensions[0] < 0)
1601
- result = `vector<${typeToString(type.elements)}>`;
1602
- else
1603
- result = `vector<${typeToString(type.elements)}^${type.dimensions[0]}>`;
1604
- }
1605
- } else if (type.dimensions.length === 2) {
1606
- const dims = type.dimensions;
1607
- if (type.elements === "number") {
1608
- if (dims[0] < 0 && dims[1] < 0) result = "matrix";
1609
- else result = `matrix<${dims[0]}x${dims[1]}>`;
1610
- } else {
1611
- if (dims[0] < 0 && dims[1] < 0)
1612
- result = `matrix<${typeToString(type.elements)}>`;
1613
- else
1614
- result = `matrix<${typeToString(type.elements)}^(${dims[0]}x${dims[1]})>`;
1615
- }
1616
- }
1617
- }
1618
- if (!result) {
1619
- const dimensions = type.dimensions ? type.dimensions.length === 1 ? `^${type.dimensions[0].toString()}` : `^(${type.dimensions.join("x")})` : "";
1620
- result = `list<${typeToString(type.elements)}${dimensions}>`;
1621
- }
1622
- break;
1623
- case "record":
1624
- const elements = Object.entries(type.elements).map(([key, value]) => `${key}: ${typeToString(value)}`).join(", ");
1625
- result = `record<${elements}>`;
1626
- break;
1627
- case "dictionary":
1628
- result = `dictionary<${typeToString(type.values)}>`;
1629
- break;
1630
- case "set":
1631
- result = `set<${typeToString(type.elements)}>`;
1632
- break;
1633
- case "collection":
1634
- result = `collection<${typeToString(type.elements)}>`;
1635
- break;
1636
- case "indexed_collection":
1637
- result = `indexed_collection<${typeToString(type.elements)}>`;
1638
- break;
1639
- case "tuple":
1640
- if (type.elements.length === 0) result = "tuple";
1641
- else if (type.elements.length === 1) {
1642
- const [el] = type.elements;
1643
- result = `tuple<${namedElement(el)}>`;
1644
- } else {
1645
- result = "tuple<" + type.elements.map((el) => namedElement(el)).join(", ") + ">";
1646
- }
1647
- break;
1648
- case "signature":
1649
- const args = type.args ? type.args.map((arg) => namedElement(arg)).join(", ") : "";
1650
- const optArgs = type.optArgs ? type.optArgs.map((arg) => namedElement(arg) + "?").join(", ") : "";
1651
- const varArg = type.variadicArg ? type.variadicMin === 0 ? `${namedElement(type.variadicArg)}*` : `${namedElement(type.variadicArg)}+` : "";
1652
- const argsList = [args, optArgs, varArg].filter((s) => s).join(", ");
1653
- result = `(${argsList}) -> ${typeToString(type.result)}`;
1654
- break;
1655
- default:
1656
- result = "error";
1657
- }
1658
- if (precedence > 0 && precedence > getPrecedence(type.kind))
1659
- return `(${result})`;
1660
- return result;
1661
- }
1662
- function namedElement(el) {
1663
- if (el.name) return `${el.name}: ${typeToString(el.type)}`;
1664
- return typeToString(el.type);
1665
- }
1666
- function symbolName(name) {
1667
- if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) return name;
1668
- return `\`${name}\``;
1669
- }
1670
- function getPrecedence(kind) {
1671
- switch (kind) {
1672
- case "negation":
1673
- return NEGATION_PRECEDENCE;
1674
- case "union":
1675
- return UNION_PRECEDENCE;
1676
- case "intersection":
1677
- return INTERSECTION_PRECEDENCE;
1678
- case "list":
1679
- return LIST_PRECEDENCE;
1680
- case "record":
1681
- return RECORD_PRECEDENCE;
1682
- case "dictionary":
1683
- return DICTIONARY_PRECEDENCE;
1684
- case "set":
1685
- return SET_PRECEDENCE;
1686
- case "collection":
1687
- case "indexed_collection":
1688
- return COLLECTION_PRECEDENCE;
1689
- case "tuple":
1690
- return TUPLE_PRECEDENCE;
1691
- case "signature":
1692
- return SIGNATURE_PRECEDENCE;
1693
- case "value":
1694
- return VALUE_PRECEDENCE;
1695
- default:
1696
- return 0;
1697
- }
1698
- }
1699
-
1700
- // src/common/fuzzy-string-match.ts
1701
- function levenshtein(source, target) {
1702
- if (source === target) return 0;
1703
- if (source.length === 0) return target.length;
1704
- if (target.length === 0) return source.length;
1705
- let prevRow = Array.from(
1706
- { length: source.length + 1 },
1707
- (_, j) => j
1708
- );
1709
- let currRow = new Array(source.length + 1);
1710
- for (let i = 1; i <= target.length; i++) {
1711
- currRow[0] = i;
1712
- for (let j = 1; j <= source.length; j++) {
1713
- const cost = source[j - 1] === target[i - 1] ? 0 : 1;
1714
- currRow[j] = Math.min(
1715
- prevRow[j] + 1,
1716
- // deletion
1717
- currRow[j - 1] + 1,
1718
- // insertion
1719
- prevRow[j - 1] + cost
1720
- // substitution
1721
- );
1722
- }
1723
- [prevRow, currRow] = [currRow, prevRow];
1724
- }
1725
- return prevRow[source.length];
1726
- }
1727
- function fuzzyStringMatch(invalidWord, validWords) {
1728
- const threshold = 7;
1729
- let bestMatch = null;
1730
- let minDistance = Infinity;
1731
- const invalidLength = invalidWord.length;
1732
- for (const word of validWords) {
1733
- if (Math.abs(invalidLength - word.length) > threshold) continue;
1734
- const distance = levenshtein(invalidWord, word);
1735
- if (distance === 0) return word;
1736
- if (distance <= threshold && distance < minDistance) {
1737
- minDistance = distance;
1738
- bestMatch = word;
1739
- }
1740
- }
1741
- return bestMatch;
1663
+ 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";
1742
1664
  }
1743
1665
 
1744
1666
  // src/common/type/lexer.ts
@@ -2448,19 +2370,13 @@ var Parser = class {
2448
2370
  );
2449
2371
  let dimensions;
2450
2372
  if (this.match("<")) {
2451
- dimensions = this.parseDimensionWithX();
2452
- if (!dimensions) {
2453
- dimensions = this.parseDimensions();
2454
- }
2373
+ dimensions = this.parseDimensions();
2455
2374
  if (!dimensions) {
2456
2375
  const type = this.parseUnionType();
2457
2376
  if (type) {
2458
2377
  elementType = type;
2459
2378
  if (this.match("^")) {
2460
- dimensions = this.parseDimensionWithX();
2461
- if (!dimensions) {
2462
- dimensions = this.parseDimensions();
2463
- }
2379
+ dimensions = this.parseCaretDimensions();
2464
2380
  }
2465
2381
  }
2466
2382
  }
@@ -2501,19 +2417,13 @@ var Parser = class {
2501
2417
  );
2502
2418
  let dimensions;
2503
2419
  if (this.match("<")) {
2504
- dimensions = this.parseDimensionWithX();
2505
- if (!dimensions) {
2506
- dimensions = this.parseDimensions();
2507
- }
2420
+ dimensions = this.parseDimensions();
2508
2421
  if (!dimensions) {
2509
2422
  const type = this.parseUnionType();
2510
2423
  if (type) {
2511
2424
  elementType = type;
2512
2425
  if (this.match("^")) {
2513
- dimensions = this.parseDimensionWithX();
2514
- if (!dimensions) {
2515
- dimensions = this.parseDimensions();
2516
- }
2426
+ dimensions = this.parseCaretDimensions();
2517
2427
  }
2518
2428
  }
2519
2429
  }
@@ -2544,16 +2454,30 @@ var Parser = class {
2544
2454
  return this.createNode("tensor", { elementType });
2545
2455
  }
2546
2456
  parseDimensions() {
2547
- const dimensions = [];
2548
2457
  const firstDim = this.parseDimension();
2549
2458
  if (!firstDim) return void 0;
2550
- dimensions.push(firstDim);
2551
- while (this.match("x")) {
2552
- const dim = this.parseDimension();
2553
- if (!dim) {
2554
- this.error("Expected dimension after x");
2459
+ const dimensions = [firstDim];
2460
+ for (; ; ) {
2461
+ const tok = this.current;
2462
+ if (tok.type === "IDENTIFIER" && /^(x\d+)+$/.test(tok.value)) {
2463
+ this.advance();
2464
+ for (const m of tok.value.match(/x(\d+)/g))
2465
+ dimensions.push(
2466
+ this.createNode("dimension", {
2467
+ size: parseInt(m.slice(1))
2468
+ })
2469
+ );
2470
+ } else if (tok.type === "IDENTIFIER" && tok.value === "x") {
2471
+ const next = this.lexer.peekToken();
2472
+ if (next.type !== "NUMBER_LITERAL" && next.type !== "?")
2473
+ this.error(
2474
+ "Expected a positive integer literal or `?` after x. For example: `2x3` or `2x?`"
2475
+ );
2476
+ this.advance();
2477
+ dimensions.push(this.parseDimension());
2478
+ } else {
2479
+ break;
2555
2480
  }
2556
- dimensions.push(dim);
2557
2481
  }
2558
2482
  return dimensions;
2559
2483
  }
@@ -2567,35 +2491,11 @@ var Parser = class {
2567
2491
  }
2568
2492
  return void 0;
2569
2493
  }
2570
- parseDimensionWithX() {
2571
- if (this.current.type === "NUMBER_LITERAL") {
2572
- const dimensions = [];
2573
- const firstDim = parseInt(this.advance().value);
2574
- dimensions.push(
2575
- this.createNode("dimension", { size: firstDim })
2576
- );
2577
- if (this.current.type === "IDENTIFIER" && this.current.value.startsWith("x")) {
2578
- const dimString = this.current.value;
2579
- const matches = dimString.match(/x(\d+)/g);
2580
- if (matches && matches.join("") === dimString) {
2581
- this.advance();
2582
- for (const match of matches) {
2583
- const dimValue = parseInt(match.substring(1));
2584
- dimensions.push(
2585
- this.createNode("dimension", { size: dimValue })
2586
- );
2587
- }
2588
- } else if (dimString === "x" || dimString.startsWith("x")) {
2589
- this.error(
2590
- "Expected a positive integer literal or `?` after x. For example: `2x3` or `2x?`"
2591
- );
2592
- }
2593
- }
2594
- if (dimensions.length > 1) {
2595
- return dimensions;
2596
- }
2597
- }
2598
- return void 0;
2494
+ parseCaretDimensions() {
2495
+ const paren = this.match("(");
2496
+ const dimensions = this.parseDimensions();
2497
+ if (paren) this.expect(")");
2498
+ return dimensions;
2599
2499
  }
2600
2500
  parseTupleType() {
2601
2501
  if (this.current.type === "IDENTIFIER" && this.current.value === "tuple") {
@@ -2780,6 +2680,18 @@ var Parser = class {
2780
2680
  this.expect("..");
2781
2681
  const upperBound = this.parseValue();
2782
2682
  this.expect(">");
2683
+ const lower = lowerBound?.value ?? -Infinity;
2684
+ const upper = upperBound?.value ?? Infinity;
2685
+ if (Number.isNaN(lower) || Number.isNaN(upper))
2686
+ this.error(
2687
+ "Invalid numeric type",
2688
+ "Lower and upper bounds must be valid numbers"
2689
+ );
2690
+ if (lower > upper)
2691
+ this.error(
2692
+ `Invalid range: ${lower}..${upper}`,
2693
+ "The lower bound must be less than the upper bound"
2694
+ );
2783
2695
  return this.createNode("numeric", {
2784
2696
  baseType,
2785
2697
  lowerBound,
@@ -2794,7 +2706,7 @@ var Parser = class {
2794
2706
  parsePrimitiveType() {
2795
2707
  if (this.current.type === "IDENTIFIER") {
2796
2708
  const name = this.current.value;
2797
- if (PRIMITIVE_TYPES.includes(name)) {
2709
+ if (PRIMITIVE_TYPES_SET.has(name)) {
2798
2710
  this.advance();
2799
2711
  return this.createNode("primitive", { name });
2800
2712
  }
@@ -3128,14 +3040,32 @@ function buildTypeFromAST(node, typeResolver) {
3128
3040
  }
3129
3041
 
3130
3042
  // src/common/type/parse.ts
3043
+ var TYPE_CACHE = /* @__PURE__ */ new Map();
3044
+ var TYPE_CACHE_MAX_SIZE = 2048;
3045
+ function deepFreeze(obj) {
3046
+ if (obj === null || typeof obj !== "object") return obj;
3047
+ if (Object.isFrozen(obj)) return obj;
3048
+ Object.freeze(obj);
3049
+ for (const value of Object.values(obj)) deepFreeze(value);
3050
+ return obj;
3051
+ }
3131
3052
  function parseType(s, typeResolver) {
3132
3053
  if (s === void 0) return void 0;
3133
3054
  if (isValidType(s)) return s;
3134
3055
  if (typeof s !== "string") return void 0;
3056
+ const cacheable = typeResolver === void 0;
3057
+ if (cacheable) {
3058
+ const cached = TYPE_CACHE.get(s);
3059
+ if (cached !== void 0) return cached;
3060
+ }
3135
3061
  try {
3136
3062
  const parser = new Parser(s, { typeResolver });
3137
3063
  const ast = parser.parseType();
3138
3064
  const type = buildTypeFromAST(ast, typeResolver);
3065
+ if (cacheable) {
3066
+ if (TYPE_CACHE.size >= TYPE_CACHE_MAX_SIZE) TYPE_CACHE.clear();
3067
+ TYPE_CACHE.set(s, deepFreeze(type));
3068
+ }
3139
3069
  return type;
3140
3070
  } catch (error) {
3141
3071
  throw new Error(
@@ -3210,19 +3140,54 @@ var PRIMITIVE_SUBTYPES = {
3210
3140
  color: [],
3211
3141
  expression: EXPRESSION_TYPES
3212
3142
  };
3143
+ var PRIMITIVE_SUBTYPES_CLOSURE = (() => {
3144
+ const closure = {};
3145
+ const closeOver = (t) => {
3146
+ if (closure[t]) return closure[t];
3147
+ const result = /* @__PURE__ */ new Set([t]);
3148
+ closure[t] = result;
3149
+ for (const sub2 of PRIMITIVE_SUBTYPES[t]) {
3150
+ if (sub2 === t) continue;
3151
+ for (const s of closeOver(sub2)) result.add(s);
3152
+ }
3153
+ return result;
3154
+ };
3155
+ for (const t of Object.keys(PRIMITIVE_SUBTYPES))
3156
+ closeOver(t);
3157
+ return closure;
3158
+ })();
3213
3159
  function isPrimitiveSubtype(lhs, rhs) {
3214
3160
  if (rhs === "any") return true;
3215
3161
  if (lhs === "never") return true;
3216
3162
  if (lhs === "unknown" || rhs === "unknown") return false;
3217
3163
  if (lhs === rhs) return true;
3218
- return PRIMITIVE_SUBTYPES[rhs].includes(lhs);
3164
+ return PRIMITIVE_SUBTYPES_CLOSURE[rhs].has(lhs);
3165
+ }
3166
+ function meetPrimitiveTypes(a, b) {
3167
+ if (a === b) return [a];
3168
+ const sa = PRIMITIVE_SUBTYPES_CLOSURE[a];
3169
+ const sb = PRIMITIVE_SUBTYPES_CLOSURE[b];
3170
+ if (sa.has(b)) return [b];
3171
+ if (sb.has(a)) return [a];
3172
+ const key = a < b ? `${a}|${b}` : `${b}|${a}`;
3173
+ const cached = MEET_CACHE.get(key);
3174
+ if (cached) return cached;
3175
+ const common = [];
3176
+ for (const t of sa) if (sb.has(t)) common.push(t);
3177
+ const maximals = common.filter(
3178
+ (t) => !common.some((u) => u !== t && PRIMITIVE_SUBTYPES_CLOSURE[u].has(t))
3179
+ );
3180
+ MEET_CACHE.set(key, maximals);
3181
+ return maximals;
3219
3182
  }
3183
+ var MEET_CACHE = /* @__PURE__ */ new Map();
3220
3184
  function isSubtype(lhs, rhs) {
3221
- if (typeof lhs === "string" && !PRIMITIVE_TYPES.includes(lhs))
3185
+ if (typeof lhs === "string" && !PRIMITIVE_TYPES_SET.has(lhs))
3222
3186
  lhs = parseType(lhs);
3223
- if (typeof rhs === "string" && !PRIMITIVE_TYPES.includes(rhs))
3187
+ if (typeof rhs === "string" && !PRIMITIVE_TYPES_SET.has(rhs))
3224
3188
  rhs = parseType(rhs);
3225
3189
  if (rhs === "any") return true;
3190
+ if (lhs === "never") return true;
3226
3191
  if (rhs === "never") return false;
3227
3192
  if (rhs === "error") return lhs === "error";
3228
3193
  if (rhs === "nothing") return lhs === "nothing";
@@ -3237,7 +3202,7 @@ function isSubtype(lhs, rhs) {
3237
3202
  if (typeof lhs.value === "number") {
3238
3203
  if (Number.isInteger(lhs.value))
3239
3204
  return isPrimitiveSubtype("integer", rhs);
3240
- return isPrimitiveSubtype("number", rhs);
3205
+ return isPrimitiveSubtype("real", rhs);
3241
3206
  }
3242
3207
  if (typeof lhs.value === "boolean")
3243
3208
  return isPrimitiveSubtype("boolean", rhs);
@@ -3467,7 +3432,7 @@ function isSubtype(lhs, rhs) {
3467
3432
  }
3468
3433
  function isNumeric(type) {
3469
3434
  if (typeof type === "string")
3470
- return NUMERIC_TYPES.includes(type);
3435
+ return NUMERIC_TYPES_SET.has(type);
3471
3436
  if (type.kind === "value") return typeof type.value === "number";
3472
3437
  if (type.kind === "numeric") return true;
3473
3438
  return false;
@@ -3475,7 +3440,7 @@ function isNumeric(type) {
3475
3440
  function isScalar(type) {
3476
3441
  if (isNumeric(type)) return true;
3477
3442
  if (typeof type === "string")
3478
- return SCALAR_TYPES.includes(type);
3443
+ return SCALAR_TYPES_SET.has(type);
3479
3444
  if (type.kind === "value")
3480
3445
  return ["string", "boolean", "number"].includes(typeof type.value);
3481
3446
  return false;
@@ -3483,7 +3448,7 @@ function isScalar(type) {
3483
3448
  function isCollection(type) {
3484
3449
  if (isIndexedCollection(type)) return true;
3485
3450
  if (typeof type === "string")
3486
- return COLLECTION_TYPES.includes(type);
3451
+ return COLLECTION_TYPES_SET.has(type);
3487
3452
  return ["collection", "set", "record", "dictionary"].includes(type.kind);
3488
3453
  }
3489
3454
  function isIndexedCollection(type) {
@@ -3522,7 +3487,7 @@ function narrow2(a, b) {
3522
3487
  if (b === "unknown") return a;
3523
3488
  if (isSubtype(a, b)) return a;
3524
3489
  if (isSubtype(b, a)) return b;
3525
- return superType(a, b);
3490
+ return "never";
3526
3491
  }
3527
3492
  function widen2(a, b) {
3528
3493
  if (a === b) return a;
@@ -3535,7 +3500,43 @@ function widen2(a, b) {
3535
3500
  if (b === "nothing") return a;
3536
3501
  if (isSubtype(a, b)) return b;
3537
3502
  if (isSubtype(b, a)) return a;
3538
- return superType(a, b);
3503
+ const sup = superType(a, b);
3504
+ if (LOSSY_SUPERTYPE.has(sup)) return unionTypes(a, b);
3505
+ return sup;
3506
+ }
3507
+ var LOSSY_SUPERTYPE = /* @__PURE__ */ new Set([
3508
+ "scalar",
3509
+ "value",
3510
+ "function",
3511
+ "expression",
3512
+ "collection",
3513
+ "indexed_collection",
3514
+ "list",
3515
+ "set",
3516
+ "tuple",
3517
+ "record",
3518
+ "dictionary",
3519
+ "map",
3520
+ "any"
3521
+ ]);
3522
+ function unionTypes(a, b) {
3523
+ const members = [];
3524
+ const keys = /* @__PURE__ */ new Set();
3525
+ const push = (t) => {
3526
+ if (typeof t === "object" && t.kind === "union") {
3527
+ for (const m of t.types) push(m);
3528
+ return;
3529
+ }
3530
+ const key = typeof t === "string" ? t : JSON.stringify(t);
3531
+ if (!keys.has(key)) {
3532
+ keys.add(key);
3533
+ members.push(t);
3534
+ }
3535
+ };
3536
+ push(a);
3537
+ push(b);
3538
+ if (members.length === 1) return members[0];
3539
+ return { kind: "union", types: members };
3539
3540
  }
3540
3541
  function narrow(...types) {
3541
3542
  if (types.length === 0) return "nothing";
@@ -3547,6 +3548,32 @@ function widen(...types) {
3547
3548
  if (types.length === 1) return types[0];
3548
3549
  return types.reduce((a, b) => widen2(a, b));
3549
3550
  }
3551
+ var SUPERTYPE_PROBE_ORDER = [
3552
+ "non_finite_number",
3553
+ "finite_integer",
3554
+ "integer",
3555
+ "finite_rational",
3556
+ "rational",
3557
+ "finite_real",
3558
+ "real",
3559
+ "imaginary",
3560
+ "finite_complex",
3561
+ "complex",
3562
+ "finite_number",
3563
+ "number",
3564
+ "list",
3565
+ "record",
3566
+ "dictionary",
3567
+ "set",
3568
+ "tuple",
3569
+ "indexed_collection",
3570
+ "collection",
3571
+ "scalar",
3572
+ "value",
3573
+ "function",
3574
+ "expression"
3575
+ ];
3576
+ var PRIMITIVE_SUPERTYPE_CACHE = /* @__PURE__ */ new Map();
3550
3577
  function superType(a, b) {
3551
3578
  if (a === b) return a;
3552
3579
  if (a === "any" || b === "any") return "any";
@@ -3556,34 +3583,185 @@ function superType(a, b) {
3556
3583
  if (b === "unknown") return a;
3557
3584
  if (a === "nothing") return b;
3558
3585
  if (b === "nothing") return a;
3559
- if (commonSupertype(a, b, "non_finite_number")) return "non_finite_number";
3560
- if (commonSupertype(a, b, "finite_integer")) return "finite_integer";
3561
- if (commonSupertype(a, b, "integer")) return "integer";
3562
- if (commonSupertype(a, b, "finite_rational")) return "finite_rational";
3563
- if (commonSupertype(a, b, "rational")) return "rational";
3564
- if (commonSupertype(a, b, "finite_real")) return "finite_real";
3565
- if (commonSupertype(a, b, "real")) return "real";
3566
- if (commonSupertype(a, b, "imaginary")) return "imaginary";
3567
- if (commonSupertype(a, b, "finite_complex")) return "finite_complex";
3568
- if (commonSupertype(a, b, "complex")) return "complex";
3569
- if (commonSupertype(a, b, "finite_number")) return "finite_number";
3570
- if (commonSupertype(a, b, "number")) return "number";
3571
- if (commonSupertype(a, b, "list")) return "list";
3572
- if (commonSupertype(a, b, "record")) return "record";
3573
- if (commonSupertype(a, b, "dictionary")) return "dictionary";
3574
- if (commonSupertype(a, b, "set")) return "set";
3575
- if (commonSupertype(a, b, "tuple")) return "tuple";
3576
- if (commonSupertype(a, b, "indexed_collection")) return "indexed_collection";
3577
- if (commonSupertype(a, b, "collection")) return "collection";
3578
- if (commonSupertype(a, b, "scalar")) return "scalar";
3579
- if (commonSupertype(a, b, "value")) return "value";
3580
- if (commonSupertype(a, b, "function")) return "function";
3581
- if (commonSupertype(a, b, "expression")) return "expression";
3586
+ if (typeof a === "string" && typeof b === "string") {
3587
+ const key = a < b ? `${a}|${b}` : `${b}|${a}`;
3588
+ let result = PRIMITIVE_SUPERTYPE_CACHE.get(key);
3589
+ if (result === void 0) {
3590
+ result = "any";
3591
+ for (const ancestor of SUPERTYPE_PROBE_ORDER) {
3592
+ const subtypes = PRIMITIVE_SUBTYPES_CLOSURE[ancestor];
3593
+ if (subtypes.has(a) && subtypes.has(b)) {
3594
+ result = ancestor;
3595
+ break;
3596
+ }
3597
+ }
3598
+ PRIMITIVE_SUPERTYPE_CACHE.set(key, result);
3599
+ }
3600
+ return result;
3601
+ }
3602
+ for (const ancestor of SUPERTYPE_PROBE_ORDER)
3603
+ if (isSubtype(a, ancestor) && isSubtype(b, ancestor)) return ancestor;
3582
3604
  return "any";
3583
3605
  }
3584
- function commonSupertype(a, b, ancestor) {
3585
- if (isSubtype(a, ancestor) && isSubtype(b, ancestor)) return true;
3586
- return false;
3606
+
3607
+ // src/common/type/serialize.ts
3608
+ var NEGATION_PRECEDENCE = 3;
3609
+ var UNION_PRECEDENCE = 1;
3610
+ var INTERSECTION_PRECEDENCE = 2;
3611
+ var LIST_PRECEDENCE = 4;
3612
+ var RECORD_PRECEDENCE = 5;
3613
+ var DICTIONARY_PRECEDENCE = 6;
3614
+ var SET_PRECEDENCE = 7;
3615
+ var COLLECTION_PRECEDENCE = 8;
3616
+ var TUPLE_PRECEDENCE = 9;
3617
+ var SIGNATURE_PRECEDENCE = 10;
3618
+ var VALUE_PRECEDENCE = 11;
3619
+ function typeToString(type, precedence = 0) {
3620
+ if (typeof type === "string") return type;
3621
+ let result = "";
3622
+ switch (type.kind) {
3623
+ case "value":
3624
+ if (typeof type.value === "string") result = `"${type.value}"`;
3625
+ else if (typeof type.value === "boolean")
3626
+ result = type.value ? "true" : "false";
3627
+ else result = type.value.toString();
3628
+ break;
3629
+ case "reference":
3630
+ result = type.name;
3631
+ break;
3632
+ case "negation":
3633
+ result = `!${typeToString(type.type, NEGATION_PRECEDENCE)}`;
3634
+ break;
3635
+ case "union":
3636
+ result = type.types.map((t) => typeToString(t, UNION_PRECEDENCE)).join(" | ");
3637
+ break;
3638
+ case "intersection":
3639
+ result = type.types.map((t) => typeToString(t, INTERSECTION_PRECEDENCE)).join(" & ");
3640
+ break;
3641
+ case "expression":
3642
+ result = `expression<${symbolName(type.operator)}>`;
3643
+ break;
3644
+ case "symbol":
3645
+ result = `symbol<${symbolName(type.name)}>`;
3646
+ break;
3647
+ case "numeric":
3648
+ if (Number.isFinite(type.lower) && Number.isFinite(type.upper)) {
3649
+ result = `${type.type}<${type.lower}..${type.upper}>`;
3650
+ } else if (Number.isFinite(type.lower)) {
3651
+ result = `${type.type}<${type.lower}..>`;
3652
+ } else if (Number.isFinite(type.upper)) {
3653
+ result = `${type.type}<..${type.upper}>`;
3654
+ } else {
3655
+ result = `${type.type}`;
3656
+ }
3657
+ break;
3658
+ case "list":
3659
+ if (type.dimensions && typeof type.elements === "string" && NUMERIC_TYPES_SET.has(type.elements)) {
3660
+ if (type.dimensions === void 0) {
3661
+ if (type.elements === "number") result = "tensor";
3662
+ } else if (type.dimensions.length === 1) {
3663
+ if (type.elements === "number") {
3664
+ if (type.dimensions[0] < 0) result = "vector";
3665
+ else result = `vector<${type.dimensions[0]}>`;
3666
+ } else {
3667
+ if (type.dimensions[0] < 0)
3668
+ result = `vector<${typeToString(type.elements)}>`;
3669
+ else
3670
+ result = `vector<${typeToString(type.elements)}^${type.dimensions[0]}>`;
3671
+ }
3672
+ } else if (type.dimensions.length === 2) {
3673
+ const dims = type.dimensions;
3674
+ if (type.elements === "number") {
3675
+ if (dims[0] < 0 && dims[1] < 0) result = "matrix";
3676
+ else result = `matrix<${dims[0]}x${dims[1]}>`;
3677
+ } else {
3678
+ if (dims[0] < 0 && dims[1] < 0)
3679
+ result = `matrix<${typeToString(type.elements)}>`;
3680
+ else
3681
+ result = `matrix<${typeToString(type.elements)}^(${dims[0]}x${dims[1]})>`;
3682
+ }
3683
+ }
3684
+ }
3685
+ if (!result) {
3686
+ const dimensions = type.dimensions ? type.dimensions.length === 1 ? `^${type.dimensions[0].toString()}` : `^(${type.dimensions.join("x")})` : "";
3687
+ result = `list<${typeToString(type.elements)}${dimensions}>`;
3688
+ }
3689
+ break;
3690
+ case "record":
3691
+ const elements = Object.entries(type.elements).map(([key, value]) => `${key}: ${typeToString(value)}`).join(", ");
3692
+ result = `record<${elements}>`;
3693
+ break;
3694
+ case "dictionary":
3695
+ result = `dictionary<${typeToString(type.values)}>`;
3696
+ break;
3697
+ case "set":
3698
+ result = `set<${typeToString(type.elements)}>`;
3699
+ break;
3700
+ case "collection":
3701
+ result = `collection<${typeToString(type.elements)}>`;
3702
+ break;
3703
+ case "indexed_collection":
3704
+ result = `indexed_collection<${typeToString(type.elements)}>`;
3705
+ break;
3706
+ case "tuple":
3707
+ if (type.elements.length === 0) result = "tuple";
3708
+ else if (type.elements.length === 1) {
3709
+ const [el] = type.elements;
3710
+ result = `tuple<${namedElement(el)}>`;
3711
+ } else {
3712
+ result = "tuple<" + type.elements.map((el) => namedElement(el)).join(", ") + ">";
3713
+ }
3714
+ break;
3715
+ case "signature":
3716
+ const args = type.args ? type.args.map((arg) => namedElement(arg)).join(", ") : "";
3717
+ const optArgs = type.optArgs ? type.optArgs.map((arg) => namedElement(arg) + "?").join(", ") : "";
3718
+ const varArg = type.variadicArg ? type.variadicMin === 0 ? `${namedElement(type.variadicArg)}*` : `${namedElement(type.variadicArg)}+` : "";
3719
+ const argsList = [args, optArgs, varArg].filter((s) => s).join(", ");
3720
+ result = `(${argsList}) -> ${typeToString(type.result)}`;
3721
+ break;
3722
+ default:
3723
+ result = "error";
3724
+ }
3725
+ if (precedence > 0 && precedence > getPrecedence(type.kind))
3726
+ return `(${result})`;
3727
+ return result;
3728
+ }
3729
+ function namedElement(el) {
3730
+ if (el.name) return `${el.name}: ${typeToString(el.type)}`;
3731
+ return typeToString(el.type);
3732
+ }
3733
+ function symbolName(name) {
3734
+ if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) return name;
3735
+ return `\`${name}\``;
3736
+ }
3737
+ function getPrecedence(kind) {
3738
+ switch (kind) {
3739
+ case "negation":
3740
+ return NEGATION_PRECEDENCE;
3741
+ case "union":
3742
+ return UNION_PRECEDENCE;
3743
+ case "intersection":
3744
+ return INTERSECTION_PRECEDENCE;
3745
+ case "list":
3746
+ return LIST_PRECEDENCE;
3747
+ case "record":
3748
+ return RECORD_PRECEDENCE;
3749
+ case "dictionary":
3750
+ return DICTIONARY_PRECEDENCE;
3751
+ case "set":
3752
+ return SET_PRECEDENCE;
3753
+ case "collection":
3754
+ case "indexed_collection":
3755
+ return COLLECTION_PRECEDENCE;
3756
+ case "tuple":
3757
+ return TUPLE_PRECEDENCE;
3758
+ case "signature":
3759
+ return SIGNATURE_PRECEDENCE;
3760
+ case "value":
3761
+ return VALUE_PRECEDENCE;
3762
+ default:
3763
+ return 0;
3764
+ }
3587
3765
  }
3588
3766
 
3589
3767
  // src/common/type/utils.ts
@@ -3609,7 +3787,7 @@ function collectionElementType(type) {
3609
3787
  if (type.kind === "set") return type.elements;
3610
3788
  if (type.kind === "tuple") return widen(...type.elements.map((x) => x.type));
3611
3789
  if (type.kind === "dictionary")
3612
- return parseType(`tuple<string, ${type.values}>`);
3790
+ return parseType(`tuple<string, ${typeToString(type.values)}>`);
3613
3791
  if (type.kind === "record") {
3614
3792
  return parseType(
3615
3793
  `tuple<string, ${typeToString(widen(...Object.values(type.elements)))}>`
@@ -3692,6 +3870,12 @@ function sym(expr) {
3692
3870
  return expr?._kind === "symbol" ? expr.symbol : void 0;
3693
3871
  }
3694
3872
 
3873
+ // src/compute-engine/boxed-expression/constraint-subject.ts
3874
+ var EMPTY_FACT_INDEX = Object.freeze({
3875
+ bySubject: /* @__PURE__ */ new Map(),
3876
+ membership: /* @__PURE__ */ new Map()
3877
+ });
3878
+
3695
3879
  // src/compute-engine/boxed-expression/stochastic-equal.ts
3696
3880
  var WELL_KNOWN_POINTS = [
3697
3881
  0,
@@ -3940,6 +4124,7 @@ function applicable(fn) {
3940
4124
  }
3941
4125
 
3942
4126
  // src/compute-engine/collection-utils.ts
4127
+ var MAX_SIZE_EAGER_COLLECTION = 100;
3943
4128
  function isFiniteIndexedCollection(col) {
3944
4129
  return (col.isFiniteCollection ?? false) && col.isIndexedCollection;
3945
4130
  }
@@ -4568,12 +4753,14 @@ function dictionaryFromExpression(expr) {
4568
4753
  if (expr === null) return null;
4569
4754
  if (isDictionaryObject(expr)) return expr;
4570
4755
  const kv = keyValuePair(expr);
4571
- if (kv) return { [kv[0]]: kv[1] };
4756
+ if (kv)
4757
+ return {
4758
+ dict: { [kv[0]]: expressionToDictionaryValue(kv[1]) ?? "Nothing" }
4759
+ };
4572
4760
  if (operator(expr) === "Dictionary") {
4573
4761
  const dict = {};
4574
- const ops = operands(expr);
4575
- for (let i = 1; i < nops(expr); i++) {
4576
- const kv2 = keyValuePair(ops[i]);
4762
+ for (const op of operands(expr)) {
4763
+ const kv2 = keyValuePair(op);
4577
4764
  if (kv2) {
4578
4765
  dict[kv2[0]] = expressionToDictionaryValue(kv2[1]) ?? "Nothing";
4579
4766
  }
@@ -5511,15 +5698,16 @@ var DEFINITIONS_CORE = [
5511
5698
  precedence: ASSIGNMENT_PRECEDENCE,
5512
5699
  parse: parseAssign
5513
5700
  },
5514
- // General colon operator (type annotation, mapping notation)
5515
- // Precedence below assignment (260) so `:=` takes priority,
5516
- // and below arrows (270) so `f: A \to B` parses as `Colon(f, To(A, B))`
5701
+ // General colon operator (type annotation, mapping notation, Desmos piecewise)
5702
+ // Precedence below comparisons (245) so `cond : val` (Desmos compact piecewise)
5703
+ // parses as `Colon(cond, val)`, and below arrows (270) so
5704
+ // `f: A \to B` parses as `Colon(f, To(A, B))`.
5517
5705
  {
5518
5706
  name: "Colon",
5519
5707
  latexTrigger: ":",
5520
5708
  kind: "infix",
5521
5709
  associativity: "right",
5522
- precedence: 250,
5710
+ precedence: 240,
5523
5711
  serialize: (serializer, expr) => joinLatex([
5524
5712
  serializer.serialize(operand(expr, 1)),
5525
5713
  "\\colon",
@@ -5530,7 +5718,7 @@ var DEFINITIONS_CORE = [
5530
5718
  latexTrigger: "\\colon",
5531
5719
  kind: "infix",
5532
5720
  associativity: "right",
5533
- precedence: 250,
5721
+ precedence: 240,
5534
5722
  parse: "Colon"
5535
5723
  },
5536
5724
  {
@@ -6506,6 +6694,7 @@ var DEFINITIONS_CORE = [
6506
6694
  }
6507
6695
  }
6508
6696
  if (!variable) return null;
6697
+ if (symbol(variable) === null) return null;
6509
6698
  parser.skipSpace();
6510
6699
  const fn = parser.parseExpression({ minPrec: 740 });
6511
6700
  if (!fn) return null;
@@ -6692,7 +6881,7 @@ function parseTextRun(parser, style) {
6692
6881
  if (runs.length === 1) body = runs[0];
6693
6882
  else {
6694
6883
  if (runs.every((x) => stringValue(x) !== null))
6695
- body = "'" + runs.map((x) => stringValue(x)).join() + "'";
6884
+ body = "'" + runs.map((x) => stringValue(x)).join("") + "'";
6696
6885
  else body = ["Text", ...runs];
6697
6886
  }
6698
6887
  return style ? ["Annotated", body, dictionaryFromEntries(style)] : body;
@@ -7100,7 +7289,10 @@ function parseForComprehension(parser, lhs, until) {
7100
7289
  p.skipVisualSpace();
7101
7290
  const isComma = p.peek === ",";
7102
7291
  p.index = saved;
7103
- return isComma;
7292
+ if (isComma) return true;
7293
+ if (peekKeyword(p, "where")) return true;
7294
+ if (peekKeyword(p, "with")) return true;
7295
+ return false;
7104
7296
  }
7105
7297
  };
7106
7298
  const elements = [];
@@ -7141,6 +7333,25 @@ function parseWhereExpression(parser, lhs, until) {
7141
7333
  parser.skipVisualSpace();
7142
7334
  } while (parser.match(","));
7143
7335
  if (bindings.length === 0) return null;
7336
+ const forStart = parser.index;
7337
+ if (matchKeyword(parser, "for")) {
7338
+ const loop = parseForComprehension(parser, lhs, until);
7339
+ if (loop) {
7340
+ const block2 = [];
7341
+ for (const b of bindings) {
7342
+ const normalized = normalizeLocalAssign(b);
7343
+ if (operator(normalized) === "Assign") {
7344
+ block2.push(["Declare", operand(normalized, 1)]);
7345
+ block2.push(normalized);
7346
+ } else {
7347
+ block2.push(normalized);
7348
+ }
7349
+ }
7350
+ block2.push(loop);
7351
+ return ["Block", ...block2];
7352
+ }
7353
+ parser.index = forStart;
7354
+ }
7144
7355
  const block = [];
7145
7356
  for (const b of bindings) {
7146
7357
  const normalized = normalizeLocalAssign(b);
@@ -7354,6 +7565,17 @@ function parseIntervalBody(body, openLeft, openRight) {
7354
7565
  const upperExpr = openRight ? ["Open", upper] : upper;
7355
7566
  return ["Interval", lowerExpr, upperExpr];
7356
7567
  }
7568
+ var COMPARISON_HEADS = /* @__PURE__ */ new Set([
7569
+ "Less",
7570
+ "LessEqual",
7571
+ "Greater",
7572
+ "GreaterEqual",
7573
+ "Equal",
7574
+ "NotEqual",
7575
+ "And",
7576
+ "Or",
7577
+ "Not"
7578
+ ]);
7357
7579
  var DEFINITIONS_SETS = [
7358
7580
  //
7359
7581
  // Constants
@@ -7612,18 +7834,58 @@ var DEFINITIONS_SETS = [
7612
7834
  closeTrigger: "}",
7613
7835
  parse: (_parser, body) => {
7614
7836
  if (isEmptySequence(body)) return "EmptySet";
7837
+ if (operator(body) == "Delimiter" && stringValue(operand(body, 2)) === ",") {
7838
+ body = operand(body, 1);
7839
+ }
7615
7840
  const h = operator(body);
7616
- if (h === "Divides" || h === "Colon") {
7841
+ if (h === "Divides") {
7617
7842
  const expr = operand(body, 1);
7618
7843
  const condition = operand(body, 2);
7619
7844
  if (expr !== null && condition !== null)
7620
7845
  return ["Set", expr, ["Condition", condition]];
7621
7846
  }
7622
- if (operator(body) == "Delimiter" && stringValue(operand(body, 2)) === ",") {
7623
- body = operand(body, 1);
7847
+ if (h === "Colon") {
7848
+ const lhs = operand(body, 1);
7849
+ const rhs = operand(body, 2);
7850
+ if (lhs !== null && rhs !== null) {
7851
+ const lhsOp = operator(lhs);
7852
+ if (lhsOp !== null && COMPARISON_HEADS.has(lhsOp)) {
7853
+ return ["Which", lhs, rhs];
7854
+ }
7855
+ return ["Set", lhs, ["Condition", rhs]];
7856
+ }
7857
+ }
7858
+ if (h === "Sequence") {
7859
+ const elements = operands(body);
7860
+ const colonElements = elements.filter((el) => operator(el) === "Colon");
7861
+ const allPiecewise = colonElements.length > 0 && colonElements.every((el) => {
7862
+ const lhs = operand(el, 1);
7863
+ const lhsOp = lhs !== null ? operator(lhs) : null;
7864
+ return lhsOp !== null && COMPARISON_HEADS.has(lhsOp);
7865
+ });
7866
+ if (allPiecewise) {
7867
+ const whichOps = [];
7868
+ for (let i = 0; i < elements.length; i++) {
7869
+ const el = elements[i];
7870
+ if (operator(el) === "Colon") {
7871
+ const cond = operand(el, 1);
7872
+ const val = operand(el, 2);
7873
+ if (cond === null || val === null) {
7874
+ return ["Set", ...elements];
7875
+ }
7876
+ whichOps.push(cond, val);
7877
+ } else {
7878
+ if (i !== elements.length - 1) {
7879
+ return ["Set", ...elements];
7880
+ }
7881
+ whichOps.push("True", el);
7882
+ }
7883
+ }
7884
+ return ["Which", ...whichOps];
7885
+ }
7886
+ return ["Set", ...elements];
7624
7887
  }
7625
- if (operator(body) !== "Sequence") return ["Set", body];
7626
- return ["Set", ...operands(body)];
7888
+ return ["Set", body];
7627
7889
  },
7628
7890
  serialize: (serializer, expr) => {
7629
7891
  if (nops(expr) === 2 && operator(operand(expr, 2)) === "Condition") {
@@ -8152,6 +8414,8 @@ function serializeMultiply(serializer, expr) {
8152
8414
  const h = operator(arg);
8153
8415
  if (prevWasNumber && (h === "Divide" || h === "Rational")) {
8154
8416
  result = latexTemplate(serializer.options.multiply, result, term);
8417
+ } else if (/^\d/.test(term)) {
8418
+ result = latexTemplate(serializer.options.multiply, result, term);
8155
8419
  } else if (!serializer.options.invisibleMultiply) {
8156
8420
  result = joinLatex([result, term]);
8157
8421
  } else {
@@ -9597,7 +9861,9 @@ function parseTrig(op) {
9597
9861
  minPrec: MULTIPLICATION_PRECEDENCE,
9598
9862
  condition: (parser2) => trigCommands[parser2.peek] || (until?.condition?.(parser2) ?? false)
9599
9863
  });
9600
- const appliedFn = args === null ? fn : typeof fn === "string" ? [fn, ...args] : ["Apply", fn, ...args];
9864
+ const isTwoArgArctan = args?.length === 2 && (fn === "Arctan" || Array.isArray(fn) && fn[0] === "InverseFunction" && fn[1] === "Tan");
9865
+ const head = isTwoArgArctan ? "Arctan2" : fn;
9866
+ const appliedFn = args === null ? fn : typeof head === "string" ? [head, ...args] : ["Apply", head, ...args];
9601
9867
  return sup === null ? appliedFn : ["Power", appliedFn, sup];
9602
9868
  };
9603
9869
  }
@@ -11720,10 +11986,17 @@ var DEFINITIONS_OTHERS = [
11720
11986
  // The capitalized library entries already exist; these are pure parse
11721
11987
  // aliases so the lowercase names don't land in `unsupported-operator`.
11722
11988
  // ---------------------------------------------------------------------------
11989
+ { latexTrigger: "\\operatorname{count}", parse: "Length" },
11723
11990
  { latexTrigger: "\\operatorname{random}", parse: "Random" },
11724
11991
  { latexTrigger: "\\operatorname{shuffle}", parse: "Shuffle" },
11725
11992
  { latexTrigger: "\\operatorname{repeat}", parse: "Repeat" },
11726
11993
  { latexTrigger: "\\operatorname{join}", parse: "Join" },
11994
+ { latexTrigger: "\\operatorname{range}", parse: "Range" },
11995
+ // Note: `\operatorname{with}` (Desmos's local-binding clause) is intentionally
11996
+ // NOT registered here. Use the math-notation equivalent `\operatorname{where}`
11997
+ // (with `\coloneq` for bindings), or register `with` as a custom dictionary
11998
+ // entry at the integration layer — see the "Desmos-Specific Syntax — Prefer
11999
+ // Custom LaTeX Dictionary" section in COMPUTE_ENGINE.md for a worked example.
11727
12000
  // ---------------------------------------------------------------------------
11728
12001
  // Geometric primitive heads. Registered as known typed heads so consumers
11729
12002
  // can branch on the operator name; CE itself doesn't render them. The
@@ -11876,6 +12149,30 @@ var POSSIBLE_EMOJI = `(?:${ZWJ_ELEMENT})(${ZWJ}${ZWJ_ELEMENT})*`;
11876
12149
  var SOME_EMOJI = new RegExp(`(?:${POSSIBLE_EMOJI})+`, "u");
11877
12150
  var EMOJIS = new RegExp(`^(?:${POSSIBLE_EMOJI})+$`, "u");
11878
12151
 
12152
+ // src/compute-engine/latex-syntax/parse.ts
12153
+ var PARSE_TOKEN_EXCLUDED = /* @__PURE__ */ new Set([
12154
+ ...'!"#$%&(),/;:?@[]\\`|~'.split(""),
12155
+ "\\left",
12156
+ "\\bigl",
12157
+ "\\mleft"
12158
+ ]);
12159
+ var TEX_UNIT_TOKENS = [
12160
+ "pt",
12161
+ "em",
12162
+ "mu",
12163
+ "ex",
12164
+ "mm",
12165
+ "cm",
12166
+ "in",
12167
+ "bp",
12168
+ "sp",
12169
+ "dd",
12170
+ "cc",
12171
+ "pc",
12172
+ "nc",
12173
+ "nd"
12174
+ ].map((unit) => [...unit]);
12175
+
11879
12176
  // src/compute-engine/boxed-expression/utils.ts
11880
12177
  function isValueDef(def) {
11881
12178
  return def !== void 0 && "value" in def;
@@ -11911,6 +12208,50 @@ function flatten(ops, operator2, canonicalize = true) {
11911
12208
  return ys;
11912
12209
  }
11913
12210
 
12211
+ // src/common/fuzzy-string-match.ts
12212
+ function levenshtein(source, target) {
12213
+ if (source === target) return 0;
12214
+ if (source.length === 0) return target.length;
12215
+ if (target.length === 0) return source.length;
12216
+ let prevRow = Array.from(
12217
+ { length: source.length + 1 },
12218
+ (_, j) => j
12219
+ );
12220
+ let currRow = new Array(source.length + 1);
12221
+ for (let i = 1; i <= target.length; i++) {
12222
+ currRow[0] = i;
12223
+ for (let j = 1; j <= source.length; j++) {
12224
+ const cost = source[j - 1] === target[i - 1] ? 0 : 1;
12225
+ currRow[j] = Math.min(
12226
+ prevRow[j] + 1,
12227
+ // deletion
12228
+ currRow[j - 1] + 1,
12229
+ // insertion
12230
+ prevRow[j - 1] + cost
12231
+ // substitution
12232
+ );
12233
+ }
12234
+ [prevRow, currRow] = [currRow, prevRow];
12235
+ }
12236
+ return prevRow[source.length];
12237
+ }
12238
+ function fuzzyStringMatch(invalidWord, validWords) {
12239
+ const threshold = 7;
12240
+ let bestMatch = null;
12241
+ let minDistance = Infinity;
12242
+ const invalidLength = invalidWord.length;
12243
+ for (const word of validWords) {
12244
+ if (Math.abs(invalidLength - word.length) > threshold) continue;
12245
+ const distance = levenshtein(invalidWord, word);
12246
+ if (distance === 0) return word;
12247
+ if (distance <= threshold && distance < minDistance) {
12248
+ minDistance = distance;
12249
+ bestMatch = word;
12250
+ }
12251
+ }
12252
+ return bestMatch;
12253
+ }
12254
+
11914
12255
  // src/compute-engine/boxed-expression/validate.ts
11915
12256
  function checkArity(ce, ops, count) {
11916
12257
  ops = flatten(ops);
@@ -12853,12 +13194,240 @@ Complex["NAN"] = new Complex(NaN, NaN);
12853
13194
  Complex["EPSILON"] = 1e-15;
12854
13195
 
12855
13196
  // src/compute-engine/boxed-expression/numerics.ts
13197
+ function asSmallInteger(expr) {
13198
+ if (expr === void 0 || expr === null) return null;
13199
+ if (typeof expr === "number") {
13200
+ if (Number.isInteger(expr) && expr >= -SMALL_INTEGER && expr <= SMALL_INTEGER)
13201
+ return expr;
13202
+ return null;
13203
+ }
13204
+ if (!isNumber(expr)) return null;
13205
+ const num = expr.numericValue;
13206
+ if (typeof num === "number") {
13207
+ if (Number.isInteger(num) && num >= -SMALL_INTEGER && num <= SMALL_INTEGER)
13208
+ return num;
13209
+ return null;
13210
+ }
13211
+ if (num.im !== 0) return null;
13212
+ const n = num.re;
13213
+ if (Number.isInteger(n) && n >= -SMALL_INTEGER && n <= SMALL_INTEGER)
13214
+ return Number(n);
13215
+ return null;
13216
+ }
12856
13217
  function toInteger(expr) {
12857
13218
  if (!isNumber(expr)) return null;
12858
13219
  const num = expr.numericValue;
12859
13220
  return Math.round(typeof num === "number" ? num : num.re);
12860
13221
  }
12861
13222
 
13223
+ // src/compute-engine/library/logic-analysis.ts
13224
+ function filterValuesWithCondition(values, variable, conditionExpr, _ce) {
13225
+ return values.filter((value) => {
13226
+ const substituted = conditionExpr.subs({ [variable]: value });
13227
+ const result = substituted.evaluate();
13228
+ return sym(result) === "True";
13229
+ });
13230
+ }
13231
+ function extractFiniteDomainWithReason(condition, ce) {
13232
+ if (condition.operator !== "Element") {
13233
+ return { status: "error", reason: "expected-element-expression" };
13234
+ }
13235
+ if (!isFunction2(condition)) {
13236
+ return { status: "error", reason: "expected-element-expression" };
13237
+ }
13238
+ const variable = isSymbol2(condition.op1) ? condition.op1.symbol : void 0;
13239
+ if (!variable) {
13240
+ return { status: "error", reason: "expected-index-variable" };
13241
+ }
13242
+ const domain = condition.op2;
13243
+ if (!domain) {
13244
+ return { status: "error", reason: "expected-domain" };
13245
+ }
13246
+ const maybeCondition = condition.op3;
13247
+ const filterCondition = condition.nops >= 3 && maybeCondition && sym(maybeCondition) !== "Nothing" ? maybeCondition : null;
13248
+ const successResult = (values) => {
13249
+ if (filterCondition) {
13250
+ const filteredValues = filterValuesWithCondition(
13251
+ values,
13252
+ variable,
13253
+ filterCondition,
13254
+ ce
13255
+ );
13256
+ return { status: "success", variable, values: filteredValues };
13257
+ }
13258
+ return { status: "success", variable, values };
13259
+ };
13260
+ if (domain.operator === "Set" || domain.operator === "List") {
13261
+ const values = isFunction2(domain) ? domain.ops : void 0;
13262
+ if (values && values.length <= 1e3) {
13263
+ if (domain.operator === "List" && values.length === 2) {
13264
+ const start = asSmallInteger(values[0]);
13265
+ const end = asSmallInteger(values[1]);
13266
+ if (start !== null && end !== null) {
13267
+ const count = end - start + 1;
13268
+ if (count > 0 && count <= 1e3) {
13269
+ const rangeValues = [];
13270
+ for (let i = start; i <= end; i++) {
13271
+ rangeValues.push(ce.number(i));
13272
+ }
13273
+ return successResult(rangeValues);
13274
+ }
13275
+ if (count > 1e3) {
13276
+ return {
13277
+ status: "non-enumerable",
13278
+ variable,
13279
+ domain,
13280
+ reason: "domain-too-large"
13281
+ };
13282
+ }
13283
+ }
13284
+ }
13285
+ return successResult([...values]);
13286
+ }
13287
+ if (values && values.length > 1e3) {
13288
+ return {
13289
+ status: "non-enumerable",
13290
+ variable,
13291
+ domain,
13292
+ reason: "domain-too-large"
13293
+ };
13294
+ }
13295
+ return { status: "error", reason: "empty-domain" };
13296
+ }
13297
+ if (isFunction2(domain, "Range")) {
13298
+ const start = asSmallInteger(domain.op1);
13299
+ const end = asSmallInteger(domain.op2);
13300
+ const step = domain.ops.length >= 3 ? asSmallInteger(domain.op3) : 1;
13301
+ if (start !== null && end !== null && step !== null && step !== 0) {
13302
+ const count = Math.floor((end - start) / step) + 1;
13303
+ if (count > 0 && count <= 1e3) {
13304
+ const values = [];
13305
+ for (let i = start; step > 0 ? i <= end : i >= end; i += step) {
13306
+ values.push(ce.number(i));
13307
+ }
13308
+ return successResult(values);
13309
+ }
13310
+ if (count > 1e3) {
13311
+ return {
13312
+ status: "non-enumerable",
13313
+ variable,
13314
+ domain,
13315
+ reason: "domain-too-large"
13316
+ };
13317
+ }
13318
+ }
13319
+ return {
13320
+ status: "non-enumerable",
13321
+ variable,
13322
+ domain,
13323
+ reason: "non-integer-bounds"
13324
+ };
13325
+ }
13326
+ if (isFunction2(domain, "Interval")) {
13327
+ let op1 = domain.op1;
13328
+ let op2 = domain.op2;
13329
+ let openStart = false;
13330
+ let openEnd = false;
13331
+ if (isFunction2(op1, "Open")) {
13332
+ openStart = true;
13333
+ op1 = op1.op1;
13334
+ } else if (isFunction2(op1, "Closed")) {
13335
+ op1 = op1.op1;
13336
+ }
13337
+ if (isFunction2(op2, "Open")) {
13338
+ openEnd = true;
13339
+ op2 = op2.op1;
13340
+ } else if (isFunction2(op2, "Closed")) {
13341
+ op2 = op2.op1;
13342
+ }
13343
+ let start = asSmallInteger(op1);
13344
+ let end = asSmallInteger(op2);
13345
+ if (start !== null && end !== null) {
13346
+ if (openStart) start += 1;
13347
+ if (openEnd) end -= 1;
13348
+ const count = end - start + 1;
13349
+ if (count > 0 && count <= 1e3) {
13350
+ const values = [];
13351
+ for (let i = start; i <= end; i++) {
13352
+ values.push(ce.number(i));
13353
+ }
13354
+ return successResult(values);
13355
+ }
13356
+ if (count > 1e3) {
13357
+ return {
13358
+ status: "non-enumerable",
13359
+ variable,
13360
+ domain,
13361
+ reason: "domain-too-large"
13362
+ };
13363
+ }
13364
+ }
13365
+ return {
13366
+ status: "non-enumerable",
13367
+ variable,
13368
+ domain,
13369
+ reason: "non-integer-bounds"
13370
+ };
13371
+ }
13372
+ const domainSymbol = sym(domain);
13373
+ if (domainSymbol) {
13374
+ const knownInfiniteSets = [
13375
+ "Integers",
13376
+ "NonNegativeIntegers",
13377
+ "PositiveIntegers",
13378
+ "NegativeIntegers",
13379
+ "Rationals",
13380
+ "Reals",
13381
+ "PositiveReals",
13382
+ "NonNegativeReals",
13383
+ "NegativeReals",
13384
+ "NonPositiveReals",
13385
+ "ExtendedReals",
13386
+ "Complexes",
13387
+ "ImaginaryNumbers",
13388
+ "Numbers",
13389
+ "ExtendedComplexes",
13390
+ "AlgebraicNumbers",
13391
+ "TranscendentalNumbers"
13392
+ ];
13393
+ if (knownInfiniteSets.includes(domainSymbol)) {
13394
+ return {
13395
+ status: "non-enumerable",
13396
+ variable,
13397
+ domain,
13398
+ reason: "infinite-domain"
13399
+ };
13400
+ }
13401
+ const domainValue = domain.value;
13402
+ if (domainValue && domainValue.operator === "Set" && isFunction2(domainValue)) {
13403
+ const values = domainValue.ops;
13404
+ if (values && values.length <= 1e3) {
13405
+ return successResult([...values]);
13406
+ }
13407
+ if (values && values.length > 1e3) {
13408
+ return {
13409
+ status: "non-enumerable",
13410
+ variable,
13411
+ domain,
13412
+ reason: "domain-too-large"
13413
+ };
13414
+ }
13415
+ }
13416
+ return {
13417
+ status: "non-enumerable",
13418
+ variable,
13419
+ domain,
13420
+ reason: "unknown-domain"
13421
+ };
13422
+ }
13423
+ return {
13424
+ status: "non-enumerable",
13425
+ variable,
13426
+ domain,
13427
+ reason: "unrecognized-domain-type"
13428
+ };
13429
+ }
13430
+
12862
13431
  // src/compute-engine/numerics/interval.ts
12863
13432
  function isNumber2(expr) {
12864
13433
  return expr?._kind === "number";
@@ -12913,6 +13482,20 @@ function interval(expr) {
12913
13482
  }
12914
13483
  return void 0;
12915
13484
  }
13485
+ function intervalContains(int, val) {
13486
+ if (int.openStart ? val <= int.start : val < int.start) return false;
13487
+ if (int.openEnd ? val >= int.end : val > int.end) return false;
13488
+ return true;
13489
+ }
13490
+
13491
+ // src/compute-engine/numerics/random.ts
13492
+ function deterministicRandom(seed) {
13493
+ const v = Math.sin(seed * 12.9898) * 43758.5453;
13494
+ return v - Math.floor(v);
13495
+ }
13496
+ function nextSeed(seed) {
13497
+ return seed + 0.6180339887498949;
13498
+ }
12916
13499
 
12917
13500
  // src/compute-engine/boxed-expression/canonical-utils.ts
12918
13501
  function canonical(ce, xs, scope) {
@@ -12920,8 +13503,236 @@ function canonical(ce, xs, scope) {
12920
13503
  return xs.map((x) => ce.expr(x, { scope }));
12921
13504
  }
12922
13505
 
13506
+ // src/common/type/reduce.ts
13507
+ function reduceType(type) {
13508
+ if (typeof type === "string") {
13509
+ if (!isValidPrimitiveType(type)) return "error";
13510
+ return type;
13511
+ }
13512
+ switch (type.kind) {
13513
+ case "union":
13514
+ return reduceUnionType(type);
13515
+ case "intersection":
13516
+ return reduceIntersectionType(type);
13517
+ case "negation":
13518
+ return reduceNegationType(type);
13519
+ case "collection":
13520
+ case "indexed_collection":
13521
+ return reduceCollectionType(type.kind, type);
13522
+ case "list":
13523
+ return reduceListType(type);
13524
+ case "set":
13525
+ return reduceSetType(type);
13526
+ case "tuple":
13527
+ return reduceTupleType(type);
13528
+ case "record":
13529
+ return reduceRecordType(type);
13530
+ case "dictionary":
13531
+ return reduceDictionaryType(type);
13532
+ case "signature":
13533
+ return reduceSignatureType(type);
13534
+ case "value":
13535
+ return type;
13536
+ case "reference":
13537
+ return type;
13538
+ default:
13539
+ throw new Error(`Unknown type kind: ${type}`);
13540
+ }
13541
+ }
13542
+ function decorate(t) {
13543
+ if (typeof t !== "object") return t;
13544
+ if (Object.isFrozen(t) || Object.prototype.hasOwnProperty.call(t, "toString"))
13545
+ return t;
13546
+ Object.defineProperty(t, "toString", { value: () => typeToString(t) });
13547
+ return t;
13548
+ }
13549
+ function reduceMembers(types) {
13550
+ const result = [];
13551
+ const seen = /* @__PURE__ */ new Set();
13552
+ for (const t of types) {
13553
+ const reduced = reduceType(t);
13554
+ const key = typeof reduced === "string" ? reduced : typeToString(reduced);
13555
+ if (!seen.has(key)) {
13556
+ seen.add(key);
13557
+ result.push(reduced);
13558
+ }
13559
+ }
13560
+ return result;
13561
+ }
13562
+ function reduceNegationType(type) {
13563
+ const reducedType = reduceType(type.type);
13564
+ if (reducedType === "nothing") return "any";
13565
+ if (reducedType === "any") return "nothing";
13566
+ return decorate({ kind: "negation", type: reducedType });
13567
+ }
13568
+ function reduceUnionType(type) {
13569
+ const reducedTypes = reduceMembers(type.types);
13570
+ if (reducedTypes.length === 0) return "never";
13571
+ if (reducedTypes.some((type2) => type2 === "error")) return "error";
13572
+ if (reducedTypes.length === 1) return decorate(reducedTypes[0]);
13573
+ const acc = [];
13574
+ for (const current of reducedTypes) {
13575
+ if (acc.some((t) => isSubtype(current, t))) continue;
13576
+ for (let i = acc.length - 1; i >= 0; i--)
13577
+ if (isSubtype(acc[i], current)) acc.splice(i, 1);
13578
+ acc.push(current);
13579
+ }
13580
+ if (acc.length === 1) return decorate(acc[0]);
13581
+ return decorate({ kind: "union", types: acc });
13582
+ }
13583
+ function meet2(a, b) {
13584
+ if (isSubtype(a, b)) return a;
13585
+ if (isSubtype(b, a)) return b;
13586
+ if (typeof a === "object" && a.kind === "union") return meetUnion(a.types, b);
13587
+ if (typeof b === "object" && b.kind === "union") return meetUnion(b.types, a);
13588
+ if (typeof a === "string" && typeof b === "string") {
13589
+ const maximals = meetPrimitiveTypes(a, b);
13590
+ if (maximals.length === 0) return "nothing";
13591
+ if (maximals.length === 1) return maximals[0];
13592
+ return { kind: "union", types: maximals };
13593
+ }
13594
+ return "nothing";
13595
+ }
13596
+ function meetUnion(types, b) {
13597
+ const members = types.map((t) => meet2(t, b)).filter((t) => t !== "nothing");
13598
+ if (members.length === 0) return "nothing";
13599
+ if (members.length === 1) return members[0];
13600
+ return reduceUnionType({ kind: "union", types: members });
13601
+ }
13602
+ function reduceIntersectionType(type) {
13603
+ const reducedTypes = reduceMembers(type.types);
13604
+ if (reducedTypes.length === 0) return "nothing";
13605
+ if (reducedTypes.some((type2) => type2 === "error")) return "error";
13606
+ let result = reducedTypes[0];
13607
+ for (let i = 1; i < reducedTypes.length; i++) {
13608
+ result = meet2(result, reducedTypes[i]);
13609
+ if (result === "nothing") return "nothing";
13610
+ }
13611
+ return decorate(result);
13612
+ }
13613
+ function reduceCollectionType(kind, type) {
13614
+ const reducedType = reduceType(type.elements);
13615
+ if (reducedType === "error") return "error";
13616
+ if (reducedType === "nothing") return decorate({ kind, elements: "nothing" });
13617
+ if (reducedType === "any") return kind;
13618
+ return decorate({
13619
+ ...type,
13620
+ elements: reducedType
13621
+ });
13622
+ }
13623
+ function reduceListType(type) {
13624
+ const reducedType = reduceType(type.elements);
13625
+ if (reducedType === "error") return "error";
13626
+ if (reducedType === "nothing")
13627
+ return decorate({ kind: "list", elements: "nothing" });
13628
+ if (reducedType === "any") return "list";
13629
+ let dimensions = type.dimensions;
13630
+ if (dimensions) {
13631
+ dimensions = dimensions.filter((dim) => dim >= 1 || dim === -1);
13632
+ if (dimensions.length === 0) return "nothing";
13633
+ }
13634
+ return decorate({
13635
+ ...type,
13636
+ dimensions,
13637
+ elements: reducedType
13638
+ });
13639
+ }
13640
+ function reduceSetType(type) {
13641
+ const reducedType = reduceType(type.elements);
13642
+ if (reducedType === "error") return "error";
13643
+ if (reducedType === "nothing")
13644
+ return decorate({ kind: "set", elements: "nothing" });
13645
+ if (reducedType === "any") return "set";
13646
+ return decorate({
13647
+ ...type,
13648
+ elements: reducedType
13649
+ });
13650
+ }
13651
+ function reduceTupleType(type) {
13652
+ let reducedElements = type.elements.map((element) => ({
13653
+ ...element,
13654
+ type: reduceType(element.type)
13655
+ }));
13656
+ if (reducedElements.length === 0) return "nothing";
13657
+ if (reducedElements.some((element) => element.type === "error"))
13658
+ return "error";
13659
+ reducedElements = reducedElements.filter(
13660
+ (element) => element.type !== "nothing"
13661
+ );
13662
+ return decorate({
13663
+ ...type,
13664
+ elements: reducedElements
13665
+ });
13666
+ }
13667
+ function reduceRecordType(type) {
13668
+ let reducedElements = {};
13669
+ for (const [key, value] of Object.entries(type.elements))
13670
+ reducedElements[key] = reduceType(value);
13671
+ if (Object.values(reducedElements).some((type2) => type2 === "error"))
13672
+ return "error";
13673
+ reducedElements = Object.fromEntries(
13674
+ Object.entries(reducedElements).filter(([_, value]) => value !== "nothing")
13675
+ );
13676
+ if (Object.keys(reducedElements).length === 0) return "record";
13677
+ return decorate({
13678
+ ...type,
13679
+ elements: reducedElements
13680
+ });
13681
+ }
13682
+ function reduceDictionaryType(type) {
13683
+ const reducedValues = reduceType(type.values);
13684
+ if (reducedValues === "error") return "error";
13685
+ if (reducedValues === "nothing") return "error";
13686
+ if (reducedValues === "any" || reducedValues === "unknown") return "any";
13687
+ return decorate({ kind: "dictionary", values: reducedValues });
13688
+ }
13689
+ function reduceSignatureType(type) {
13690
+ const reducedArgs = type.args?.map((arg) => ({
13691
+ ...arg,
13692
+ type: reduceType(arg.type)
13693
+ }));
13694
+ let reducedOptArgs = type.optArgs?.map((arg) => ({
13695
+ ...arg,
13696
+ type: reduceType(arg.type)
13697
+ }));
13698
+ let reducedVarArg = type.variadicArg ? {
13699
+ ...type.variadicArg,
13700
+ type: reduceType(type.variadicArg.type)
13701
+ } : void 0;
13702
+ const reducedResult = reduceType(type.result);
13703
+ if (reducedArgs?.some((arg) => arg.type === "error")) return "error";
13704
+ if (reducedOptArgs?.some((arg) => arg.type === "error")) return "error";
13705
+ if (reducedVarArg?.type === "error") return "error";
13706
+ if (reducedResult === "error") return "error";
13707
+ reducedOptArgs = reducedOptArgs?.filter((arg) => arg.type !== "nothing");
13708
+ if (reducedArgs?.length === 0) reducedOptArgs = void 0;
13709
+ if (reducedOptArgs?.length === 0) reducedOptArgs = void 0;
13710
+ if (reducedVarArg?.type === "nothing") reducedVarArg = void 0;
13711
+ return decorate({
13712
+ ...type,
13713
+ args: reducedArgs,
13714
+ optArgs: reducedOptArgs,
13715
+ variadicArg: reducedVarArg,
13716
+ variadicMin: reducedVarArg ? type.variadicMin : void 0,
13717
+ result: reducedResult
13718
+ });
13719
+ }
13720
+
13721
+ // src/compute-engine/library/sets.ts
13722
+ function typeIntersection(a, b) {
13723
+ return reduceType({ kind: "intersection", types: [a, b] });
13724
+ }
13725
+ function typeMembership(x, t) {
13726
+ const vt = x.type;
13727
+ if (vt.matches(t)) return true;
13728
+ if (typeIntersection(vt.type, t) === "nothing") return false;
13729
+ if (isNumber(x)) return false;
13730
+ return void 0;
13731
+ }
13732
+
12923
13733
  // src/compute-engine/library/collections.ts
12924
13734
  var DEFAULT_LINSPACE_COUNT = 50;
13735
+ var SET_BASE_HANDLERS = basicIndexedCollectionHandlers();
12925
13736
  var COLLECTIONS_LIBRARY = {
12926
13737
  //
12927
13738
  // Data Structures
@@ -12944,11 +13755,38 @@ var COLLECTIONS_LIBRARY = {
12944
13755
  },
12945
13756
  // Extensional set. Elements do not repeat. The order of the elements is not significant.
12946
13757
  // For intensional set, use `Filter` with a condition, e.g. `Filter(RealNumbers, _ > 0)`
13758
+ //
13759
+ // A `Set` expression can also be a set-builder (comprehension), e.g.
13760
+ // `["Set", body, ["Element", k, domain, cond?]]` or
13761
+ // `["Set", body, ["Condition", ...]]` (see `parseSetComprehension()`).
13762
+ // Comprehensions are not literal 2-element sets: their elements are the
13763
+ // substituted bodies over the (filtered) domain.
12947
13764
  Set: {
12948
13765
  complexity: 8200,
12949
13766
  signature: "(any*) -> set",
12950
- type: (ops, { engine: _ce }) => parseType(`set<${BoxedType.widen(...ops.map((op) => op.type))}>`),
13767
+ type: (ops, { engine: _ce }) => {
13768
+ if (parseSetComprehension(ops) !== null) return parseType("set");
13769
+ return parseType(`set<${BoxedType.widen(...ops.map((op) => op.type))}>`);
13770
+ },
12951
13771
  canonical: canonicalSet,
13772
+ // The `lazy` flag suppresses the default operand evaluation: evaluating
13773
+ // the operands of a comprehension would mangle its indexing set (e.g.
13774
+ // the condition `gcd(n,k) = 1` with a free `k` evaluates to `False`).
13775
+ // Literal elements are evaluated explicitly in the `evaluate` handler.
13776
+ lazy: true,
13777
+ evaluate: (ops, { engine: ce, numericApproximation, materialization }) => {
13778
+ const comp = parseSetComprehension(ops);
13779
+ if (comp !== null) {
13780
+ const elements = enumerateSetComprehension(comp);
13781
+ if (elements === void 0 || elements.length > MAX_SIZE_EAGER_COLLECTION)
13782
+ return void 0;
13783
+ return ce.function("Set", elements);
13784
+ }
13785
+ return ce.function(
13786
+ "Set",
13787
+ ops.map((op) => op.evaluate({ numericApproximation, materialization }))
13788
+ );
13789
+ },
12952
13790
  eq: (a, b) => {
12953
13791
  if (a.operator !== b.operator) return false;
12954
13792
  if (!isFunction2(a) || !isFunction2(b)) return false;
@@ -12957,10 +13795,75 @@ var COLLECTIONS_LIBRARY = {
12957
13795
  return a.ops.every(has);
12958
13796
  },
12959
13797
  collection: {
12960
- ...basicIndexedCollectionHandlers(),
13798
+ ...SET_BASE_HANDLERS,
12961
13799
  // A set is not indexable
12962
13800
  at: void 0,
12963
- indexWhere: void 0
13801
+ indexWhere: void 0,
13802
+ // A comprehension computes its elements on demand
13803
+ isLazy: (expr) => isFunction2(expr) && parseSetComprehension(expr.ops) !== null,
13804
+ count: (expr) => {
13805
+ if (!isFunction2(expr)) return 0;
13806
+ const comp = parseSetComprehension(expr.ops);
13807
+ if (comp === null) return expr.nops;
13808
+ return enumerateSetComprehension(comp)?.length;
13809
+ },
13810
+ isEmpty: (expr) => {
13811
+ if (!isFunction2(expr)) return true;
13812
+ const comp = parseSetComprehension(expr.ops);
13813
+ if (comp === null) return expr.nops === 0;
13814
+ const elements = enumerateSetComprehension(comp);
13815
+ return elements === void 0 ? void 0 : elements.length === 0;
13816
+ },
13817
+ isFinite: (expr) => {
13818
+ if (!isFunction2(expr)) return true;
13819
+ const comp = parseSetComprehension(expr.ops);
13820
+ if (comp === null) return true;
13821
+ if (enumerateSetComprehension(comp) !== void 0) return true;
13822
+ if (comp.domain?.isFiniteCollection === true) return true;
13823
+ return void 0;
13824
+ },
13825
+ iterator: (expr) => {
13826
+ if (!isFunction2(expr)) return SET_BASE_HANDLERS.iterator(expr);
13827
+ const comp = parseSetComprehension(expr.ops);
13828
+ if (comp === null) return SET_BASE_HANDLERS.iterator(expr);
13829
+ const elements = enumerateSetComprehension(comp);
13830
+ if (elements === void 0) return void 0;
13831
+ let i = 0;
13832
+ return {
13833
+ next: () => i >= elements.length ? { value: void 0, done: true } : { value: elements[i++], done: false }
13834
+ };
13835
+ },
13836
+ // Three-valued membership: `true` when an element matches, `false`
13837
+ // only when every element is definitively different from `target`
13838
+ // (concrete values), `undefined` otherwise — e.g. a symbolic target
13839
+ // (`Element(ω, {-1, 1})`) is indeterminate, not refuted.
13840
+ contains: (expr, target) => {
13841
+ if (!isFunction2(expr)) return void 0;
13842
+ const comp = parseSetComprehension(expr.ops);
13843
+ if (comp !== null) return setComprehensionContains(comp, target);
13844
+ return literalSetContains(expr.ops, target);
13845
+ },
13846
+ elttype: (expr) => {
13847
+ if (!isFunction2(expr)) return SET_BASE_HANDLERS.elttype(expr);
13848
+ const comp = parseSetComprehension(expr.ops);
13849
+ if (comp === null) return SET_BASE_HANDLERS.elttype(expr);
13850
+ const elements = enumerateSetComprehension(comp);
13851
+ if (elements === void 0 || elements.length === 0) return "unknown";
13852
+ return widen(...elements.map((op) => op.type.type));
13853
+ }
13854
+ }
13855
+ },
13856
+ Length: {
13857
+ description: "Number of elements in a collection. Returns undefined for non-collections and for infinite collections.",
13858
+ complexity: 4e3,
13859
+ signature: "(any) -> integer",
13860
+ type: () => "integer",
13861
+ evaluate: ([xs], { engine }) => {
13862
+ if (!xs.isCollection) return void 0;
13863
+ if (xs.isEmptyCollection) return engine.Zero;
13864
+ const n = xs.count;
13865
+ if (n === void 0 || !isFinite(n)) return void 0;
13866
+ return engine.number(n);
12964
13867
  }
12965
13868
  },
12966
13869
  Tuple: {
@@ -13047,7 +13950,12 @@ var COLLECTIONS_LIBRARY = {
13047
13950
  },
13048
13951
  contains: (expr, target) => {
13049
13952
  const t = target.re;
13953
+ if (Number.isNaN(t))
13954
+ return typeMembership(target, "number") === false ? false : void 0;
13955
+ if (target.im !== 0) return false;
13050
13956
  if (!isFinite(t)) return false;
13957
+ if (isFunction2(expr) && expr.ops.some((op) => Number.isNaN(op.re)))
13958
+ return void 0;
13051
13959
  const [lower, upper, step] = range(expr);
13052
13960
  if (step === 0) return false;
13053
13961
  if (step > 0) {
@@ -13123,13 +14031,23 @@ var COLLECTIONS_LIBRARY = {
13123
14031
  signature: "(number, number) -> set<real>",
13124
14032
  canonical: ([lo, hi], { engine }) => {
13125
14033
  if (!lo || !hi) return null;
14034
+ const unwrap2 = (op) => {
14035
+ if (isFunction2(op, "Open")) return [op.op1, true];
14036
+ if (isFunction2(op, "Closed")) return [op.op1, false];
14037
+ return [op, false];
14038
+ };
14039
+ const [loVal, loOpen] = unwrap2(lo);
14040
+ const [hiVal, hiOpen] = unwrap2(hi);
13126
14041
  const [lower, upper] = checkTypes(
13127
14042
  engine,
13128
- [lo.canonical, hi.canonical],
14043
+ [loVal.canonical, hiVal.canonical],
13129
14044
  ["number", "number"]
13130
14045
  );
13131
14046
  if (!lower.isValid || !upper.isValid) return null;
13132
- return engine._fn("Interval", [lower, upper]);
14047
+ return engine._fn("Interval", [
14048
+ loOpen ? engine._fn("Open", [lower]) : lower,
14049
+ hiOpen ? engine._fn("Open", [upper]) : upper
14050
+ ]);
13133
14051
  },
13134
14052
  eq: (a, b) => {
13135
14053
  const intervalA = interval(a);
@@ -13164,19 +14082,32 @@ var COLLECTIONS_LIBRARY = {
13164
14082
  },
13165
14083
  isEmpty: (_expr) => {
13166
14084
  const int = interval(_expr);
13167
- if (!int) return false;
14085
+ if (!int) return void 0;
13168
14086
  if (int.openStart && int.start === int.end) return true;
13169
14087
  if (int.openEnd && int.start === int.end) return true;
13170
14088
  if (int.openStart && int.openEnd) return false;
13171
14089
  return int.start >= int.end;
13172
14090
  },
13173
14091
  isFinite: (_expr) => false,
14092
+ // Three-valued membership: `true` only when both bound checks are
14093
+ // entailed, `false` when a bound check (or the type of the target)
14094
+ // refutes membership, `undefined` otherwise (e.g. symbolic target
14095
+ // with unknown bounds). Endpoints may be ±Infinity.
13174
14096
  contains: (expr, target) => {
13175
14097
  const int = interval(expr);
13176
- if (!int) return false;
13177
- if (int.openStart && target.isLessEqual(int.start)) return false;
13178
- if (int.openEnd && target.isGreaterEqual(int.end)) return false;
13179
- return target.isGreaterEqual(int.start) && target.isLessEqual(int.end);
14098
+ if (!int) return void 0;
14099
+ if (typeMembership(target, "number") === false) return false;
14100
+ const t = target.re;
14101
+ if (!Number.isNaN(t)) {
14102
+ if (target.im !== 0) return false;
14103
+ return intervalContains(int, t);
14104
+ }
14105
+ const aboveLower = int.openStart ? target.isGreater(int.start) : target.isGreaterEqual(int.start);
14106
+ if (aboveLower === false) return false;
14107
+ const belowUpper = int.openEnd ? target.isLess(int.end) : target.isLessEqual(int.end);
14108
+ if (belowUpper === false) return false;
14109
+ if (aboveLower === true && belowUpper === true) return true;
14110
+ return void 0;
13180
14111
  },
13181
14112
  eltsgn: (expr) => {
13182
14113
  const i = interval(expr);
@@ -13216,10 +14147,12 @@ var COLLECTIONS_LIBRARY = {
13216
14147
  const upper = expr.op2.re;
13217
14148
  let count = expr.op3.re;
13218
14149
  if (!isFinite(count)) count = DEFAULT_LINSPACE_COUNT;
14150
+ count = Math.floor(count);
13219
14151
  if (!isFinite(lower) || !isFinite(upper)) return void 0;
13220
14152
  if (index < 1 || index > count) return void 0;
14153
+ if (count === 1) return expr.engine.number(lower);
13221
14154
  return expr.engine.number(
13222
- lower + (upper - lower) * (index - 1) / count
14155
+ lower + (upper - lower) * (index - 1) / (count - 1)
13223
14156
  );
13224
14157
  },
13225
14158
  iterator: (expr) => {
@@ -13238,6 +14171,8 @@ var COLLECTIONS_LIBRARY = {
13238
14171
  !isFinite(expr.op3.re) ? DEFAULT_LINSPACE_COUNT : expr.op3.re
13239
14172
  );
13240
14173
  }
14174
+ totalCount = Math.floor(totalCount);
14175
+ const denom = totalCount > 1 ? totalCount - 1 : 1;
13241
14176
  let index = 1;
13242
14177
  return {
13243
14178
  next: () => {
@@ -13246,7 +14181,7 @@ var COLLECTIONS_LIBRARY = {
13246
14181
  index += 1;
13247
14182
  return {
13248
14183
  value: expr.engine.number(
13249
- lower + (upper - lower) * (index - 1 - 1) / totalCount
14184
+ lower + (upper - lower) * (index - 1 - 1) / denom
13250
14185
  ),
13251
14186
  done: false
13252
14187
  };
@@ -13254,17 +14189,26 @@ var COLLECTIONS_LIBRARY = {
13254
14189
  };
13255
14190
  },
13256
14191
  contains: (expr, target) => {
13257
- if (!target.type.matches("finite_real")) return false;
13258
- if (!isFunction2(expr)) return false;
13259
14192
  const t = target.re;
14193
+ if (Number.isNaN(t))
14194
+ return typeMembership(target, "number") === false ? false : void 0;
14195
+ if (target.im !== 0) return false;
14196
+ if (!isFinite(t)) return false;
14197
+ if (!isFunction2(expr)) return void 0;
13260
14198
  const lower = expr.op1.re;
13261
14199
  const upper = expr.op2.re;
14200
+ if (Number.isNaN(lower) || Number.isNaN(upper)) return void 0;
13262
14201
  if (t < lower || t > upper) return false;
13263
14202
  let count = expr.op3.re;
13264
14203
  if (!isFinite(count)) count = DEFAULT_LINSPACE_COUNT;
14204
+ count = Math.floor(count);
13265
14205
  if (count === 0) return false;
13266
- const step = (upper - lower) / count;
13267
- return (t - lower) % step === 0;
14206
+ if (count === 1) return t === lower;
14207
+ const step = (upper - lower) / (count - 1);
14208
+ const k = (t - lower) / step;
14209
+ const tol = expr.engine.tolerance;
14210
+ const kRounded = Math.round(k);
14211
+ return kRounded >= 0 && kRounded <= count - 1 && Math.abs(k - kRounded) < tol;
13268
14212
  }
13269
14213
  }
13270
14214
  },
@@ -13283,8 +14227,18 @@ var COLLECTIONS_LIBRARY = {
13283
14227
  description: ["Return the number of elements in the collection."],
13284
14228
  complexity: 8200,
13285
14229
  signature: "(collection) -> integer",
13286
- evaluate: ([xs], { engine }) => xs.isEmptyCollection ? engine.Zero : engine.number(xs.count),
13287
- sgn: ([xs]) => xs.isEmptyCollection ? "zero" : "positive"
14230
+ evaluate: ([xs], { engine }) => {
14231
+ if (xs.isEmptyCollection) return engine.Zero;
14232
+ const n = xs.count;
14233
+ if (n === void 0) return void 0;
14234
+ return engine.number(n);
14235
+ },
14236
+ sgn: ([xs]) => {
14237
+ const empty = xs.isEmptyCollection;
14238
+ if (empty === true) return "zero";
14239
+ if (empty === false) return "positive";
14240
+ return void 0;
14241
+ }
13288
14242
  },
13289
14243
  IsEmpty: {
13290
14244
  description: ["Return True if the collection is empty, False otherwise."],
@@ -13400,7 +14354,13 @@ var COLLECTIONS_LIBRARY = {
13400
14354
  },
13401
14355
  collection: {
13402
14356
  isLazy: (_expr) => true,
13403
- count: (_expr) => Infinity,
14357
+ count: (expr) => {
14358
+ if (!isFunction2(expr)) return void 0;
14359
+ if (!expr.op1.isFiniteCollection) return Infinity;
14360
+ let n = 0;
14361
+ for (const _ of expr.each()) n++;
14362
+ return n;
14363
+ },
13404
14364
  contains: (expr, target) => {
13405
14365
  if (!isFunction2(expr)) return false;
13406
14366
  if (!expr.contains(target)) return false;
@@ -13509,24 +14469,26 @@ var COLLECTIONS_LIBRARY = {
13509
14469
  type: (ops) => parseType(functionResult(ops[1].type.type) ?? "unknown"),
13510
14470
  evaluate: ([collection, fn, initial], { engine: ce }) => {
13511
14471
  if (!collection.isFiniteCollection) return void 0;
14472
+ const hasInitial = initial !== void 0;
13512
14473
  initial ??= ce.Nothing;
13513
14474
  if (initial.type.matches("real") && collection.type.matches(ce.type("collection<real>"))) {
13514
14475
  const compiled = ce._compile(fn);
13515
- if (compiled.calling !== "lambda" || !compiled.run) return void 0;
13516
- return run(
13517
- (function* () {
13518
- let accumulator = initial.re;
13519
- let first = true;
13520
- for (const item of collection.each()) {
13521
- if (first) accumulator = item.re;
13522
- else accumulator = compiled.run(accumulator, item.re);
13523
- first = false;
13524
- yield;
13525
- }
13526
- return ce.expr(accumulator);
13527
- })(),
13528
- ce._timeRemaining
13529
- );
14476
+ if (compiled.calling === "lambda" && compiled.run) {
14477
+ return run(
14478
+ (function* () {
14479
+ let accumulator = hasInitial ? initial.re : NaN;
14480
+ let first = true;
14481
+ for (const item of collection.each()) {
14482
+ if (first && !hasInitial) accumulator = item.re;
14483
+ else accumulator = compiled.run(accumulator, item.re);
14484
+ first = false;
14485
+ yield;
14486
+ }
14487
+ return ce.expr(accumulator);
14488
+ })(),
14489
+ ce._timeRemaining
14490
+ );
14491
+ }
13530
14492
  }
13531
14493
  const f = applicable(fn);
13532
14494
  return run(
@@ -13589,10 +14551,12 @@ var COLLECTIONS_LIBRARY = {
13589
14551
  description: [
13590
14552
  "Access an element of an indexed collection.",
13591
14553
  "If the index is negative, it is counted from the end.",
13592
- "Multiple indices can be provided to access nested collections (e.g., matrices)."
14554
+ "Multiple indices can be provided to access nested collections (e.g., matrices).",
14555
+ "If the index is a finite collection of booleans, returns the elements where the mask is True.",
14556
+ "If the index is a finite collection of integers, returns the elements at those indices."
13593
14557
  ],
13594
14558
  complexity: 8200,
13595
- signature: "(value: indexed_collection, index: (number|string)+) -> unknown",
14559
+ signature: "(value: indexed_collection, index: (number|string|indexed_collection)+) -> unknown",
13596
14560
  type: ([xs]) => xs.operatorDefinition?.collection?.elttype?.(xs) ?? collectionElementType(xs.type.type) ?? "any",
13597
14561
  evaluate: (ops, { engine: ce }) => {
13598
14562
  let expr = ops[0];
@@ -13603,12 +14567,39 @@ var COLLECTIONS_LIBRARY = {
13603
14567
  if (!at) return void 0;
13604
14568
  const opAtIndex = ops[index];
13605
14569
  const s = isString(opAtIndex) ? opAtIndex.string : void 0;
13606
- if (s !== void 0) expr = at(expr, s) ?? ce.Nothing;
13607
- else {
13608
- const i = ops[index].re;
13609
- if (!Number.isInteger(i)) return void 0;
13610
- expr = at(expr, i) ?? ce.Nothing;
14570
+ if (s !== void 0) {
14571
+ expr = at(expr, s) ?? ce.Nothing;
14572
+ index += 1;
14573
+ continue;
14574
+ }
14575
+ if (opAtIndex.isCollection && opAtIndex.isFiniteCollection) {
14576
+ const indices = Array.from(opAtIndex.each());
14577
+ const isMask = indices.every((m) => {
14578
+ const name = sym(m);
14579
+ return name === "True" || name === "False";
14580
+ });
14581
+ const picked = [];
14582
+ if (isMask) {
14583
+ indices.forEach((m, i2) => {
14584
+ if (sym(m) !== "True") return;
14585
+ const v = at(expr, i2 + 1);
14586
+ if (v !== void 0) picked.push(v);
14587
+ });
14588
+ } else {
14589
+ for (const m of indices) {
14590
+ const k = m.re;
14591
+ if (!Number.isInteger(k)) return void 0;
14592
+ const v = at(expr, k);
14593
+ if (v !== void 0) picked.push(v);
14594
+ }
14595
+ }
14596
+ expr = ce._fn("List", picked);
14597
+ index += 1;
14598
+ continue;
13611
14599
  }
14600
+ const i = opAtIndex.re;
14601
+ if (!Number.isInteger(i)) return void 0;
14602
+ expr = at(expr, i) ?? ce.Nothing;
13612
14603
  index += 1;
13613
14604
  }
13614
14605
  return expr;
@@ -13619,7 +14610,7 @@ var COLLECTIONS_LIBRARY = {
13619
14610
  description: ["Return `n` elements from a collection."],
13620
14611
  complexity: 8200,
13621
14612
  signature: "(xs: indexed_collection, count: number) -> indexed_collection",
13622
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
14613
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
13623
14614
  evaluate: (ops, { engine, materialization: eager }) => {
13624
14615
  if (!eager) return void 0;
13625
14616
  const takeExpr = engine._fn("Take", ops);
@@ -13666,7 +14657,7 @@ var COLLECTIONS_LIBRARY = {
13666
14657
  description: ["Return the collection without the first n elements."],
13667
14658
  complexity: 8200,
13668
14659
  signature: "(xs: indexed_collection, count: number) -> indexed_collection",
13669
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
14660
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
13670
14661
  collection: {
13671
14662
  isLazy: (_expr) => true,
13672
14663
  count: (expr) => {
@@ -13690,10 +14681,13 @@ var COLLECTIONS_LIBRARY = {
13690
14681
  const [xs, nExpr] = expr.ops;
13691
14682
  const n = toInteger(nExpr) ?? 0;
13692
14683
  if (n <= 0) return xs.each();
14684
+ const count = xs.count;
13693
14685
  let index = n + 1;
13694
14686
  return {
13695
14687
  next: () => {
13696
- const value = expr.op1.at(index++);
14688
+ if (count !== void 0 && index > count)
14689
+ return { value: void 0, done: true };
14690
+ const value = xs.at(index++);
13697
14691
  if (value === void 0) return { value: void 0, done: true };
13698
14692
  return { value, done: false };
13699
14693
  }
@@ -13704,7 +14698,13 @@ var COLLECTIONS_LIBRARY = {
13704
14698
  if (!isFunction2(expr)) return void 0;
13705
14699
  const [xs, nExpr] = expr.ops;
13706
14700
  const n = toInteger(nExpr) ?? 0;
13707
- if (n <= 0) return void 0;
14701
+ if (n <= 0) return xs.at(index);
14702
+ if (index < 0) {
14703
+ const count = xs.count;
14704
+ if (count !== void 0 && -index > count - n) return void 0;
14705
+ return xs.at(index);
14706
+ }
14707
+ if (index < 1) return void 0;
13708
14708
  return xs.at(index + n);
13709
14709
  }
13710
14710
  }
@@ -13786,11 +14786,15 @@ var COLLECTIONS_LIBRARY = {
13786
14786
  iterator: (expr) => {
13787
14787
  if (!isFunction2(expr))
13788
14788
  return { next: () => ({ value: void 0, done: true }) };
14789
+ const op1 = expr.op1;
14790
+ const count = op1.count;
14791
+ let index = 2;
13789
14792
  return {
13790
14793
  next: () => {
13791
- let index = 1;
13792
- const value = expr.op1.at(index > 0 ? index + 1 : index);
13793
- if (!value) return { value: void 0, done: true };
14794
+ if (count !== void 0 && index > count)
14795
+ return { value: void 0, done: true };
14796
+ const value = op1.at(index);
14797
+ if (value === void 0) return { value: void 0, done: true };
13794
14798
  index += 1;
13795
14799
  return { value, done: false };
13796
14800
  }
@@ -13862,17 +14866,24 @@ var COLLECTIONS_LIBRARY = {
13862
14866
  ],
13863
14867
  complexity: 8200,
13864
14868
  signature: "(value: indexed_collection, start: number, end: number) -> list",
13865
- type: ([xs]) => parseType(`list<${collectionElementType(xs.type.type)}>`),
14869
+ type: ([xs]) => parseType(
14870
+ `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`
14871
+ ),
13866
14872
  collection: {
13867
14873
  isLazy: (_expr) => true,
13868
14874
  count: (expr) => {
13869
14875
  if (!isFunction2(expr)) return void 0;
13870
- const start = toInteger(expr.op2) ?? 1;
13871
14876
  const count = expr.op1.count;
13872
14877
  if (count === void 0) return void 0;
13873
- const end = toInteger(expr.op3) ?? count;
13874
- if (start < 1) return Math.max(0, end + start - 1);
13875
- return Math.max(0, Math.min(end, count) - start + 1);
14878
+ let start = toInteger(expr.op2) ?? 1;
14879
+ if (start < 1) start = count + 1 + start;
14880
+ if (start < 1) start = 1;
14881
+ if (start > count) return 0;
14882
+ let end = toInteger(expr.op3) ?? count;
14883
+ if (end < 1) end = count + 1 + end;
14884
+ if (end < 1) end = 1;
14885
+ if (end > count) end = count;
14886
+ return Math.max(0, end - start + 1);
13876
14887
  },
13877
14888
  isFinite: (_expr) => true,
13878
14889
  at: (expr, index) => {
@@ -13888,6 +14899,11 @@ var COLLECTIONS_LIBRARY = {
13888
14899
  if (end < 1) end = count + 1 + end;
13889
14900
  if (end < 1) end = 1;
13890
14901
  if (end > count) end = count;
14902
+ const length = end - start + 1;
14903
+ if (length <= 0) return void 0;
14904
+ if (index < 0) index = length + 1 + index;
14905
+ if (index < 1 || index > length) return void 0;
14906
+ return expr.op1.at(start + index - 1);
13891
14907
  },
13892
14908
  iterator: (expr) => {
13893
14909
  if (!isFunction2(expr))
@@ -14151,7 +15167,7 @@ var COLLECTIONS_LIBRARY = {
14151
15167
  for (const item of xs.each()) {
14152
15168
  const pred = sym(f([item]));
14153
15169
  if (pred === "True") indices.push(ce.number(index));
14154
- if (pred !== "False")
15170
+ else if (pred !== "False")
14155
15171
  throw new Error(
14156
15172
  `Filter predicate must return "True" or "False". ${spellCheckMessage(
14157
15173
  fn
@@ -14194,16 +15210,26 @@ var COLLECTIONS_LIBRARY = {
14194
15210
  },
14195
15211
  // Randomize the order of the elements in the collection.
14196
15212
  Shuffle: {
14197
- description: "Randomize the order of the elements in the collection.",
15213
+ description: "Randomize the order of the elements in the collection. With an optional `seed` argument, the shuffle is deterministic.",
14198
15214
  complexity: 8200,
14199
- signature: "(indexed_collection) -> indexed_collection",
15215
+ signature: "(indexed_collection, real?) -> indexed_collection",
14200
15216
  type: (ops) => ops[0].type,
14201
- evaluate: ([xs], { engine: ce }) => {
15217
+ evaluate: ([xs, seedOp], { engine: ce }) => {
14202
15218
  if (!xs.isFiniteCollection) return void 0;
14203
15219
  const data = Array.from(xs.each());
14204
- for (let i = data.length - 1; i > 0; i--) {
14205
- const j = Math.floor(Math.random() * (i + 1));
14206
- [data[i], data[j]] = [data[j], data[i]];
15220
+ const seed = seedOp?.re;
15221
+ if (seed !== void 0 && !Number.isNaN(seed)) {
15222
+ let s = seed;
15223
+ for (let i = data.length - 1; i > 0; i--) {
15224
+ const j = Math.floor(deterministicRandom(s) * (i + 1));
15225
+ [data[i], data[j]] = [data[j], data[i]];
15226
+ s = nextSeed(s);
15227
+ }
15228
+ } else {
15229
+ for (let i = data.length - 1; i > 0; i--) {
15230
+ const j = Math.floor(Math.random() * (i + 1));
15231
+ [data[i], data[j]] = [data[j], data[i]];
15232
+ }
14207
15233
  }
14208
15234
  return ce.function(xs.operator, data);
14209
15235
  }
@@ -14270,7 +15296,9 @@ var COLLECTIONS_LIBRARY = {
14270
15296
  if (t === "string")
14271
15297
  return parseType(`tuple<list<string>, list<integer>>`);
14272
15298
  return parseType(
14273
- `tuple<list<${collectionElementType(t)}>, list<integer>>`
15299
+ `tuple<list<${typeToString(
15300
+ collectionElementType(t) ?? "any"
15301
+ )}>, list<integer>>`
14274
15302
  );
14275
15303
  },
14276
15304
  evaluate: (ops, { engine: ce }) => {
@@ -14286,7 +15314,7 @@ var COLLECTIONS_LIBRARY = {
14286
15314
  description: "Return a list of the unique elements of the collection.",
14287
15315
  complexity: 8200,
14288
15316
  signature: "(collection) -> list",
14289
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
15317
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
14290
15318
  evaluate: (ops, { engine: ce }) => {
14291
15319
  if (!ops[0].isFiniteCollection) return void 0;
14292
15320
  const [values, _counts] = tally(ops[0]);
@@ -14298,7 +15326,7 @@ var COLLECTIONS_LIBRARY = {
14298
15326
  wikidata: "Q381060",
14299
15327
  complexity: 8200,
14300
15328
  signature: "(collection, integer | function) -> list",
14301
- type: ([xs]) => `list<${collectionElementType(xs.type.type)}>`,
15329
+ type: ([xs]) => `list<${typeToString(collectionElementType(xs.type.type) ?? "any")}>`,
14302
15330
  evaluate: ([xs, arg], { engine: ce }) => {
14303
15331
  if (!xs.isFiniteCollection) return void 0;
14304
15332
  const k = toInteger(arg);
@@ -14388,11 +15416,25 @@ var COLLECTIONS_LIBRARY = {
14388
15416
  count: zipCount,
14389
15417
  isFinite: (expr) => {
14390
15418
  if (!isFunction2(expr)) return void 0;
14391
- return expr.ops.every((x) => x.isFiniteCollection);
15419
+ if (expr.nops === 0) return true;
15420
+ let anyUnknown = false;
15421
+ for (const x of expr.ops) {
15422
+ const f = x.isFiniteCollection;
15423
+ if (f === true) return true;
15424
+ if (f === void 0) anyUnknown = true;
15425
+ }
15426
+ return anyUnknown ? void 0 : false;
14392
15427
  },
14393
15428
  isEmpty: (expr) => {
14394
15429
  if (!isFunction2(expr)) return void 0;
14395
- return expr.nops === 0 || expr.ops.every((x) => x.isEmptyCollection);
15430
+ if (expr.nops === 0) return true;
15431
+ let anyUnknown = false;
15432
+ for (const x of expr.ops) {
15433
+ const e = x.isEmptyCollection;
15434
+ if (e === true) return true;
15435
+ if (e === void 0) anyUnknown = true;
15436
+ }
15437
+ return anyUnknown ? void 0 : false;
14396
15438
  },
14397
15439
  iterator: (expr) => {
14398
15440
  if (!isFunction2(expr))
@@ -14472,32 +15514,74 @@ var COLLECTIONS_LIBRARY = {
14472
15514
  }
14473
15515
  }
14474
15516
  },
14475
- // Repeat(x) -> [x, x, ...]
14476
- // This is an infinite series. Can use Take(Repeat(x), n) to get a finite series
14477
- // x is evaluated once. Although could use Hold()?
14478
- // So that First(Repeat(Hold(Random(5))), 10) would return 10 random numbers...
15517
+ // Repeat(x) -> [x, x, ...] — infinite sequence
15518
+ // Repeat(x, n) -> [x, x, ..., x] — finite list of n copies
14479
15519
  Repeat: {
14480
- description: "Produce an infinite sequence by repeating a single value.",
15520
+ 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.",
14481
15521
  complexity: 8200,
14482
- signature: "(value: any) -> list",
15522
+ signature: "(value: any, count: integer?) -> list",
15523
+ evaluate: (ops, { engine }) => {
15524
+ if (ops.length !== 2) return void 0;
15525
+ const raw = toInteger(ops[1]);
15526
+ if (raw === null) return void 0;
15527
+ const n = Math.max(0, raw);
15528
+ if (n > engine.maxCollectionSize) return void 0;
15529
+ return engine._fn("List", Array(n).fill(ops[0]));
15530
+ },
14483
15531
  collection: {
14484
- isLazy: (_expr) => true,
14485
- count: () => Infinity,
14486
- isEmpty: (_expr) => false,
14487
- // Never empty
14488
- isFinite: () => false,
14489
- // Infinite collection
15532
+ isLazy: (expr) => isFunction2(expr) && expr.ops?.length === 1,
15533
+ count: (expr) => {
15534
+ if (!isFunction2(expr)) return void 0;
15535
+ if (expr.ops?.length === 2) {
15536
+ const n = toInteger(expr.op2);
15537
+ return n !== null ? Math.max(0, n) : void 0;
15538
+ }
15539
+ return Infinity;
15540
+ },
15541
+ isEmpty: (expr) => {
15542
+ if (!isFunction2(expr)) return void 0;
15543
+ if (expr.ops?.length === 2) {
15544
+ const n = toInteger(expr.op2);
15545
+ return n !== null ? n <= 0 : void 0;
15546
+ }
15547
+ return false;
15548
+ },
15549
+ isFinite: (expr) => isFunction2(expr) && expr.ops?.length === 2,
14490
15550
  contains: (expr, target) => {
14491
15551
  if (!isFunction2(expr)) return false;
15552
+ if (expr.ops?.length === 2) {
15553
+ const n = toInteger(expr.op2);
15554
+ if (n !== null && n <= 0) return false;
15555
+ }
14492
15556
  return expr.op1.isSame(target);
14493
15557
  },
14494
15558
  iterator: (expr) => {
14495
15559
  if (!isFunction2(expr))
14496
15560
  return { next: () => ({ value: void 0, done: true }) };
15561
+ if (expr.ops?.length === 2) {
15562
+ const n = toInteger(expr.op2);
15563
+ if (n === null) {
15564
+ return { next: () => ({ value: void 0, done: true }) };
15565
+ }
15566
+ const count = Math.max(0, n);
15567
+ let i = 0;
15568
+ return {
15569
+ next: () => i++ < count ? { value: expr.op1, done: false } : { value: void 0, done: true }
15570
+ };
15571
+ }
14497
15572
  return { next: () => ({ value: expr.op1, done: false }) };
14498
15573
  },
14499
- at: (expr, _index) => {
15574
+ // at is 1-based (consistent with Range, Take, and other collection handlers)
15575
+ at: (expr, index) => {
14500
15576
  if (!isFunction2(expr)) return void 0;
15577
+ if (typeof index !== "number") return void 0;
15578
+ if (expr.ops?.length === 2) {
15579
+ const n = toInteger(expr.op2);
15580
+ const count = n !== null ? Math.max(0, n) : 0;
15581
+ if (index < 1 || index > count) return void 0;
15582
+ } else {
15583
+ if (index < 1) return void 0;
15584
+ }
14501
15585
  return expr.op1;
14502
15586
  }
14503
15587
  }
@@ -14510,9 +15594,22 @@ var COLLECTIONS_LIBRARY = {
14510
15594
  signature: "(list) -> list",
14511
15595
  collection: {
14512
15596
  isLazy: (_expr) => true,
14513
- count: () => Infinity,
14514
- isEmpty: (expr) => expr.isEmptyCollection,
14515
- isFinite: (expr) => !expr.isEmptyCollection,
15597
+ // Cycling a non-empty collection is infinite; cycling an empty one is
15598
+ // empty. Inspect the *underlying* collection (`op1`) reading
15599
+ // `expr.isEmptyCollection`/`expr.isFiniteCollection` here would re-enter
15600
+ // these same handlers and recurse infinitely.
15601
+ count: (expr) => {
15602
+ if (!isFunction2(expr)) return void 0;
15603
+ return expr.op1.isEmptyCollection ? 0 : Infinity;
15604
+ },
15605
+ isEmpty: (expr) => {
15606
+ if (!isFunction2(expr)) return void 0;
15607
+ return expr.op1.isEmptyCollection;
15608
+ },
15609
+ isFinite: (expr) => {
15610
+ if (!isFunction2(expr)) return void 0;
15611
+ return expr.op1.isEmptyCollection;
15612
+ },
14516
15613
  contains: (expr, target) => {
14517
15614
  if (!isFunction2(expr)) return false;
14518
15615
  return expr.op1.contains(target) ?? false;
@@ -14526,7 +15623,7 @@ var COLLECTIONS_LIBRARY = {
14526
15623
  return { next: () => ({ value: void 0, done: true }) };
14527
15624
  return {
14528
15625
  next: () => {
14529
- const i = (index - 1 - 1) % l + 1;
15626
+ const i = (index - 1) % l + 1;
14530
15627
  const value = expr.op1.at(i);
14531
15628
  if (value === void 0) return { value: void 0, done: true };
14532
15629
  index += 1;
@@ -14648,7 +15745,7 @@ var COLLECTIONS_LIBRARY = {
14648
15745
  evaluate: (ops, { engine: ce }) => {
14649
15746
  const elements = [];
14650
15747
  for (const xs of ops) {
14651
- if (xs.isCollection) elements.push(xs);
15748
+ if (!xs.isCollection) elements.push(xs);
14652
15749
  else {
14653
15750
  if (!xs.isFiniteCollection) return void 0;
14654
15751
  elements.push(...Array.from(xs.each()));
@@ -14664,7 +15761,7 @@ var COLLECTIONS_LIBRARY = {
14664
15761
  evaluate: (ops, { engine: ce }) => {
14665
15762
  const elements = [];
14666
15763
  for (const xs of ops) {
14667
- if (xs.isCollection) elements.push(xs);
15764
+ if (!xs.isCollection) elements.push(xs);
14668
15765
  else {
14669
15766
  if (!xs.isFiniteCollection) return void 0;
14670
15767
  elements.push(...Array.from(xs.each()));
@@ -14757,11 +15854,129 @@ function canonicalList(ops, { engine: ce }) {
14757
15854
  return ce._fn("List", ops);
14758
15855
  }
14759
15856
  function canonicalSet(ops, { engine }) {
15857
+ ops = ops.map((op) => op.canonical);
15858
+ if (parseSetComprehension(ops) !== null) return engine._fn("Set", [...ops]);
14760
15859
  const set = [];
14761
15860
  const has = (x) => set.some((y) => y.isSame(x));
14762
15861
  for (const op of ops) if (!has(op)) set.push(op);
14763
15862
  return engine._fn("Set", set);
14764
15863
  }
15864
+ function parseSetComprehension(ops) {
15865
+ if (ops.length !== 2) return null;
15866
+ const [body, spec] = ops;
15867
+ const canon = (x) => x.isCanonical ? x : x.canonical;
15868
+ if (isFunction2(spec, "Element") && spec.nops >= 2) {
15869
+ if (!isSymbol2(spec.op1)) return null;
15870
+ const v = spec.op1.symbol;
15871
+ if (!body.has(v)) return null;
15872
+ const cond = spec.nops >= 3 && sym(spec.op3) !== "Nothing" ? spec.op3 : void 0;
15873
+ return { body, variable: v, domain: spec.op2, condition: cond };
15874
+ }
15875
+ if (isFunction2(spec, "Condition") && spec.nops >= 1) {
15876
+ const pred = spec.op1;
15877
+ if (isFunction2(body, "Element") && body.nops === 2 && isSymbol2(body.op1)) {
15878
+ return {
15879
+ body: body.op1,
15880
+ variable: body.op1.symbol,
15881
+ domain: canon(body.op2),
15882
+ condition: canon(pred)
15883
+ };
15884
+ }
15885
+ if (isFunction2(pred, "Element") && pred.nops === 2 && isSymbol2(pred.op1)) {
15886
+ const v = pred.op1.symbol;
15887
+ if (body.has(v))
15888
+ return {
15889
+ body,
15890
+ variable: v,
15891
+ domain: canon(pred.op2),
15892
+ condition: void 0
15893
+ };
15894
+ }
15895
+ if (isFunction2(pred, "And")) {
15896
+ const memberships = pred.ops.filter(
15897
+ (x) => isFunction2(x, "Element") && x.nops === 2 && isSymbol2(x.op1) && body.has(x.op1.symbol)
15898
+ );
15899
+ const membership = memberships.length === 1 ? memberships[0] : void 0;
15900
+ if (membership && isFunction2(membership, "Element") && isSymbol2(membership.op1)) {
15901
+ const rest = pred.ops.filter((x) => x !== membership).map(canon);
15902
+ const ce = body.engine;
15903
+ const cond = rest.length === 0 ? void 0 : rest.length === 1 ? rest[0] : ce._fn("And", rest);
15904
+ return {
15905
+ body,
15906
+ variable: membership.op1.symbol,
15907
+ domain: canon(membership.op2),
15908
+ condition: cond
15909
+ };
15910
+ }
15911
+ }
15912
+ return {
15913
+ body,
15914
+ variable: isSymbol2(body) ? body.symbol : void 0,
15915
+ domain: void 0,
15916
+ condition: pred
15917
+ };
15918
+ }
15919
+ return null;
15920
+ }
15921
+ function enumerateSetComprehension(comp) {
15922
+ const { body, variable, domain, condition } = comp;
15923
+ if (variable === void 0 || domain === void 0) return void 0;
15924
+ const ce = body.engine;
15925
+ const extract = (dom) => extractFiniteDomainWithReason(
15926
+ ce._fn("Element", [
15927
+ ce.symbol(variable),
15928
+ dom,
15929
+ ...condition ? [condition] : []
15930
+ ]),
15931
+ ce
15932
+ );
15933
+ let result = extract(domain);
15934
+ if (result.status !== "success") {
15935
+ const evaluatedDomain = domain.evaluate();
15936
+ if (!evaluatedDomain.isSame(domain)) result = extract(evaluatedDomain);
15937
+ }
15938
+ if (result.status !== "success") return void 0;
15939
+ const isIdentity = isSymbol2(body) && body.symbol === variable;
15940
+ const elements = [];
15941
+ for (const value of result.values) {
15942
+ const x = isIdentity ? value : body.subs({ [variable]: value }).evaluate();
15943
+ if (!elements.some((y) => y.isSame(x))) elements.push(x);
15944
+ }
15945
+ return elements;
15946
+ }
15947
+ function literalSetContains(ops, target) {
15948
+ let indeterminate = false;
15949
+ for (const op of ops) {
15950
+ if (target.isSame(op)) return true;
15951
+ if (isNumber(target) && isNumber(op)) {
15952
+ const eq2 = target.isEqual(op);
15953
+ if (eq2 === true) return true;
15954
+ if (eq2 !== false) indeterminate = true;
15955
+ } else if (isString(target) && isString(op)) {
15956
+ } else {
15957
+ indeterminate = true;
15958
+ }
15959
+ }
15960
+ return indeterminate ? void 0 : false;
15961
+ }
15962
+ function setComprehensionContains(comp, target) {
15963
+ const elements = enumerateSetComprehension(comp);
15964
+ if (elements !== void 0) return literalSetContains(elements, target);
15965
+ if (comp.domain !== void 0 && comp.variable !== void 0 && isSymbol2(comp.body) && comp.body.symbol === comp.variable) {
15966
+ const inDomain = comp.domain.contains(target);
15967
+ if (inDomain === false) return false;
15968
+ let condition = true;
15969
+ if (comp.condition !== void 0) {
15970
+ if (isNumber(target) || isString(target)) {
15971
+ const result = comp.condition.subs({ [comp.variable]: target }).evaluate();
15972
+ condition = sym(result) === "True" ? true : sym(result) === "False" ? false : void 0;
15973
+ } else condition = void 0;
15974
+ }
15975
+ if (condition === false) return false;
15976
+ if (inDomain === true && condition === true) return true;
15977
+ }
15978
+ return void 0;
15979
+ }
14765
15980
  function tally(collection) {
14766
15981
  const values = [];
14767
15982
  const counts = [];
@@ -15001,7 +16216,11 @@ var BaseCompiler = class _BaseCompiler {
15001
16216
  op[1]
15002
16217
  )}`;
15003
16218
  } else {
15004
- resultStr = args.map((arg) => _BaseCompiler.compile(arg, target, op[1])).join(` ${op[0]} `);
16219
+ const rightAssoc = h === "Power";
16220
+ resultStr = args.map((arg, i) => {
16221
+ const operandPrec = rightAssoc && i < args.length - 1 ? op[1] + 1 : op[1];
16222
+ return _BaseCompiler.compile(arg, target, operandPrec);
16223
+ }).join(` ${op[0]} `);
15005
16224
  }
15006
16225
  return op[1] < prec ? `(${resultStr})` : resultStr;
15007
16226
  }
@@ -15206,6 +16425,13 @@ var BaseCompiler = class _BaseCompiler {
15206
16425
  * GLSL (no dynamic arrays, no push). A compile-time error is thrown.
15207
16426
  * TODO(E3-GLSL): support GLSL multi-Element via a pre-declared fixed-size
15208
16427
  * array or by unrolling when bounds are known at compile time.
16428
+ *
16429
+ * Known issue (imperative form): the IIFE generated by form (1) has no
16430
+ * `return` statement, so `Loop(body, Element(i, Range(lo, hi)))` compiled
16431
+ * to JS evaluates to `undefined` at runtime, while CE evaluation returns a
16432
+ * `List` of body values. See `test/compute-engine/a1-c1-compile-parity.test.ts`
16433
+ * ("Loop compiles in JS") for the verify-only test that locks in the
16434
+ * current behavior.
15209
16435
  */
15210
16436
  static compileForLoop(args, target) {
15211
16437
  if (!args[0]) throw new Error("Loop: no body");
@@ -15687,6 +16913,17 @@ function compile(expr, options) {
15687
16913
  `Compilation fallback for "${expr.operator}" (target: ${options?.to ?? "javascript"}): ${e.message}`
15688
16914
  );
15689
16915
  const ce = expr.engine;
16916
+ const target = options?.to ?? "javascript";
16917
+ if (isFunction2(expr, "Function")) {
16918
+ const lambdaRun = ((...args) => ce.function("Apply", [expr, ...args.map((a) => ce.box(a))]).evaluate().re);
16919
+ return {
16920
+ target,
16921
+ success: false,
16922
+ code: "",
16923
+ calling: "lambda",
16924
+ run: lambdaRun
16925
+ };
16926
+ }
15690
16927
  const fallbackRun = ((vars) => {
15691
16928
  ce.pushScope();
15692
16929
  try {
@@ -15699,7 +16936,7 @@ function compile(expr, options) {
15699
16936
  }
15700
16937
  });
15701
16938
  return {
15702
- target: options?.to ?? "javascript",
16939
+ target,
15703
16940
  success: false,
15704
16941
  code: "",
15705
16942
  calling: "expression",
@@ -15753,6 +16990,11 @@ function foldTerms(terms, identity, op) {
15753
16990
  if (symbolic.length === 1) return symbolic[0];
15754
16991
  return symbolic.join(op === "+" ? " + " : " * ");
15755
16992
  }
16993
+ function parenthesizeFactor(expr, code) {
16994
+ if (isFunction2(expr, "Add") || isFunction2(expr, "Subtract"))
16995
+ return `(${code})`;
16996
+ return code;
16997
+ }
15756
16998
  function tryGetComplexParts(expr, compile2) {
15757
16999
  if (isSymbol2(expr, "ImaginaryUnit")) {
15758
17000
  return { re: null, im: "1.0" };
@@ -15777,7 +17019,9 @@ function tryGetComplexParts(expr, compile2) {
15777
17019
  if (remaining.length === 0) {
15778
17020
  return { re: null, im: formatFloat(iScale) };
15779
17021
  }
15780
- const compiledFactors = remaining.map((r) => compile2(r));
17022
+ const compiledFactors = remaining.map(
17023
+ (r) => parenthesizeFactor(r, compile2(r))
17024
+ );
15781
17025
  if (iScale !== 1) compiledFactors.unshift(formatFloat(iScale));
15782
17026
  const imCode = foldTerms(compiledFactors, "1.0", "*");
15783
17027
  return { re: null, im: imCode };
@@ -19294,9 +20538,14 @@ var lanczos_7_c = [
19294
20538
  ];
19295
20539
  function gammaln(z) {
19296
20540
  if (z < 0) return NaN;
20541
+ let shift = 0;
20542
+ while (z < 10) {
20543
+ shift += Math.log(z);
20544
+ z += 1;
20545
+ }
19297
20546
  const pi = Math.PI;
19298
20547
  const z3 = z * z * z;
19299
- 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);
20548
+ 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;
19300
20549
  }
19301
20550
  function gamma(z) {
19302
20551
  if (z < 0.5) return Math.PI / (Math.sin(Math.PI * z) * gamma(1 - z));
@@ -19307,31 +20556,62 @@ function gamma(z) {
19307
20556
  const t = z + gammaG + 0.5;
19308
20557
  return Math.sqrt(2 * Math.PI) * Math.pow(t, z + 0.5) * Math.exp(-t) * x;
19309
20558
  }
20559
+ function erfInvApprox(x) {
20560
+ const a = 0.147;
20561
+ const ln1mx2 = Math.log(1 - x * x);
20562
+ const b = 2 / (Math.PI * a) + ln1mx2 / 2;
20563
+ return Math.sign(x) * Math.sqrt(Math.sqrt(b * b - ln1mx2 / a) - b);
20564
+ }
19310
20565
  function erfInv(x) {
19311
- const pi = Math.PI;
19312
- const pi2 = pi * pi;
19313
- const pi3 = pi2 * pi;
19314
- const x2 = x * x;
19315
- const x3 = x * x2;
19316
- const x5 = x3 * x2;
19317
- const x7 = x5 * x2;
19318
- 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);
20566
+ if (Number.isNaN(x) || x < -1 || x > 1) return NaN;
20567
+ if (x === 0) return 0;
20568
+ if (x === 1) return Infinity;
20569
+ if (x === -1) return -Infinity;
20570
+ const sign2 = x < 0 ? -1 : 1;
20571
+ const ax = Math.abs(x);
20572
+ let y = erfInvApprox(ax);
20573
+ const c = Math.sqrt(Math.PI) / 2;
20574
+ for (let i = 0; i < 4; i++) y -= (erf(y) - ax) * c * Math.exp(y * y);
20575
+ return sign2 * y;
19319
20576
  }
19320
20577
  function erfc(x) {
19321
- return 1 - erf(x);
20578
+ if (Number.isNaN(x)) return NaN;
20579
+ if (!Number.isFinite(x)) return x > 0 ? 0 : 2;
20580
+ if (x < 0) return 2 - erfc(-x);
20581
+ if (x < 2) return 1 - erf(x);
20582
+ const tiny = 1e-300;
20583
+ let f = x === 0 ? tiny : x;
20584
+ let c = f;
20585
+ let d = 0;
20586
+ for (let k = 1; k <= 500; k++) {
20587
+ const a = k / 2;
20588
+ d = x + a * d;
20589
+ if (d === 0) d = tiny;
20590
+ d = 1 / d;
20591
+ c = x + a / c;
20592
+ if (c === 0) c = tiny;
20593
+ const delta = c * d;
20594
+ f *= delta;
20595
+ if (Math.abs(delta - 1) < 1e-17) break;
20596
+ }
20597
+ return Math.exp(-x * x) / (Math.sqrt(Math.PI) * f);
19322
20598
  }
19323
20599
  function erf(x) {
19324
- const a1 = 0.254829592;
19325
- const a2 = -0.284496736;
19326
- const a3 = 1.421413741;
19327
- const a4 = -1.453152027;
19328
- const a5 = 1.061405429;
19329
- const p = 0.3275911;
20600
+ if (Number.isNaN(x)) return NaN;
20601
+ if (x === 0) return 0;
20602
+ if (!Number.isFinite(x)) return x > 0 ? 1 : -1;
19330
20603
  const sign2 = x < 0 ? -1 : 1;
19331
- x = Math.abs(x);
19332
- const t = 1 / (1 + p * x);
19333
- const y = ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t;
19334
- return sign2 * (1 - y * Math.exp(-x * x));
20604
+ const ax = Math.abs(x);
20605
+ if (ax >= 6) return sign2;
20606
+ const x2 = ax * ax;
20607
+ let term = ax;
20608
+ let sum = ax;
20609
+ for (let n = 1; n < 200; n++) {
20610
+ term *= 2 * x2 / (2 * n + 1);
20611
+ sum += term;
20612
+ if (term < sum * 1e-18) break;
20613
+ }
20614
+ return sign2 * (2 / Math.sqrt(Math.PI)) * Math.exp(-x2) * sum;
19335
20615
  }
19336
20616
  var EULER_MASCHERONI = 0.5772156649015329;
19337
20617
  var BERNOULLI_2K = [
@@ -19917,7 +21197,7 @@ function fresnelS(x) {
19917
21197
  const t = x2 * x2;
19918
21198
  return sign2 * x * x2 * polevl(t, SN) / polevl(t, SD);
19919
21199
  }
19920
- if (x < 36) {
21200
+ if (x < 36974) {
19921
21201
  const x2 = x * x;
19922
21202
  const t = Math.PI * x2;
19923
21203
  const u = 1 / (t * t);
@@ -19942,7 +21222,7 @@ function fresnelC(x) {
19942
21222
  const t = x2 * x2;
19943
21223
  return sign2 * x * polevl(t, CN) / polevl(t, CD);
19944
21224
  }
19945
- if (x < 36) {
21225
+ if (x < 36974) {
19946
21226
  const x2 = x * x;
19947
21227
  const t = Math.PI * x2;
19948
21228
  const u = 1 / (t * t);
@@ -20033,6 +21313,7 @@ function populationStandardDeviation(values) {
20033
21313
  function kurtosis(values) {
20034
21314
  let sum = 0;
20035
21315
  let sum2 = 0;
21316
+ let sum3 = 0;
20036
21317
  let sum4 = 0;
20037
21318
  let count = 0;
20038
21319
  for (const op of values) {
@@ -20040,12 +21321,16 @@ function kurtosis(values) {
20040
21321
  if (!Number.isFinite(v)) return NaN;
20041
21322
  sum += v;
20042
21323
  sum2 += v * v;
21324
+ sum3 += v * v * v;
20043
21325
  sum4 += v * v * v * v;
20044
21326
  count++;
20045
21327
  }
20046
21328
  if (count === 0) return NaN;
20047
- const s2 = (sum2 - sum * sum / count) / (count - 1);
20048
- return (sum4 - 4 * sum * sum2 / count + 6 * sum * sum * sum / count / count - 3 * sum * sum * sum * sum / count / count / count) / (s2 * s2);
21329
+ const n = count;
21330
+ const m = sum / n;
21331
+ const m2 = (sum2 - sum * sum / n) / n;
21332
+ const m4 = (sum4 - 4 * m * sum3 + 6 * m * m * sum2 - 4 * m * m * m * sum + n * m * m * m * m) / n;
21333
+ return m4 / (m2 * m2);
20049
21334
  }
20050
21335
  function skewness(values) {
20051
21336
  let sum = 0;
@@ -20061,9 +21346,11 @@ function skewness(values) {
20061
21346
  count++;
20062
21347
  }
20063
21348
  if (count === 0) return NaN;
20064
- const s2 = (sum2 - sum * sum / count) / (count - 1);
20065
- const s3 = (sum3 - sum2 * sum / count) / (count - 1);
20066
- return s3 / Math.pow(s2, 3 / 2) * Math.sqrt(count * 1);
21349
+ const n = count;
21350
+ const m = sum / n;
21351
+ const m2 = (sum2 - sum * sum / n) / n;
21352
+ const m3 = (sum3 - 3 * m * sum2 + 3 * m * m * sum - n * m * m * m) / n;
21353
+ return m3 / Math.pow(m2, 3 / 2);
20067
21354
  }
20068
21355
  function mode(values) {
20069
21356
  const counts = {};
@@ -20090,11 +21377,8 @@ function quartiles(values) {
20090
21377
  return [q1, q2, q3];
20091
21378
  }
20092
21379
  function interquartileRange(values) {
20093
- const sorted = [...values].sort((a, b) => a - b);
20094
- const mid = Math.floor(sorted.length / 2);
20095
- const lower = sorted.slice(0, mid);
20096
- const upper = sorted.slice(mid + 1);
20097
- return median(upper) - median(lower);
21380
+ const [q1, , q3] = quartiles(values);
21381
+ return q3 - q1;
20098
21382
  }
20099
21383
 
20100
21384
  // src/compute-engine/numerics/monte-carlo.ts
@@ -20293,6 +21577,7 @@ var JAVASCRIPT_FUNCTIONS = {
20293
21577
  return `_SYS.cexp(${compile2(args[0])})`;
20294
21578
  return `Math.exp(${compile2(args[0])})`;
20295
21579
  },
21580
+ First: (args, compile2) => `${compile2(args[0])}[0]`,
20296
21581
  Floor: (args, compile2) => {
20297
21582
  if (BaseCompiler.isIntegerValued(args[0])) return compile2(args[0]);
20298
21583
  return `Math.floor(${compile2(args[0])})`;
@@ -20424,7 +21709,7 @@ var JAVASCRIPT_FUNCTIONS = {
20424
21709
  if (parseFloat(step) === 1) {
20425
21710
  const fStop = parseFloat(stop);
20426
21711
  const fStart = parseFloat(start);
20427
- if (fStop !== null && fStart !== null) {
21712
+ if (!isNaN(fStop) && !isNaN(fStart)) {
20428
21713
  if (fStop - fStart < 50) {
20429
21714
  return `[${Array.from(
20430
21715
  { length: fStop - fStart + 1 },
@@ -20435,9 +21720,9 @@ var JAVASCRIPT_FUNCTIONS = {
20435
21720
  }, (_, i) => ${start} + i)`;
20436
21721
  }
20437
21722
  return `Array.from({length: ${stop} - ${start} + 1
20438
- }, (_, i) => ${start} + i)`;
21723
+ }, (_e, i) => ${start} + i)`;
20439
21724
  }
20440
- return `Array.from({length: Math.floor((${stop} - ${start}) / ${step}) + 1}, (_, i) => ${start} + i * ${step})`;
21725
+ return `Array.from({length: Math.floor((${stop} - ${start}) / ${step}) + 1}, (_e, i) => ${start} + i * ${step})`;
20441
21726
  },
20442
21727
  Root: ([arg, exp3], compile2) => {
20443
21728
  if (arg === null) throw new Error("Root: no argument");
@@ -20451,7 +21736,20 @@ var JAVASCRIPT_FUNCTIONS = {
20451
21736
  if (nConst !== void 0) return `Math.pow(${compile2(arg)}, ${1 / nConst})`;
20452
21737
  return `Math.pow(${compile2(arg)}, 1 / (${compile2(exp3)}))`;
20453
21738
  },
20454
- Random: "Math.random",
21739
+ Random: (args, compile2) => {
21740
+ if (args.length === 0) return "Math.random()";
21741
+ if (args.length === 2) {
21742
+ const m = compile2(args[0]);
21743
+ const n = compile2(args[1]);
21744
+ return `((${m}) + Math.floor(Math.random() * ((${n}) - (${m}))))`;
21745
+ }
21746
+ const arg = args[0];
21747
+ if (BaseCompiler.isIntegerValued(arg)) {
21748
+ return `Math.floor(Math.random() * (${compile2(arg)}))`;
21749
+ }
21750
+ const a = compile2(arg);
21751
+ return `(() => { const _s = (${a}) * 12.9898; const _v = Math.sin(_s) * 43758.5453; return _v - Math.floor(_v); })()`;
21752
+ },
20455
21753
  Round: (args, compile2) => {
20456
21754
  if (BaseCompiler.isIntegerValued(args[0])) return compile2(args[0]);
20457
21755
  return `Math.round(${compile2(args[0])})`;
@@ -20479,6 +21777,7 @@ var JAVASCRIPT_FUNCTIONS = {
20479
21777
  if (BaseCompiler.isComplexValued(arg)) return `_SYS.csech(${compile2(arg)})`;
20480
21778
  return `1 / Math.cosh(${compile2(arg)})`;
20481
21779
  },
21780
+ Second: (args, compile2) => `${compile2(args[0])}[1]`,
20482
21781
  Heaviside: "_SYS.heaviside",
20483
21782
  Sign: "Math.sign",
20484
21783
  Sinc: "_SYS.sinc",
@@ -20511,6 +21810,7 @@ var JAVASCRIPT_FUNCTIONS = {
20511
21810
  return `_SYS.ctanh(${compile2(args[0])})`;
20512
21811
  return `Math.tanh(${compile2(args[0])})`;
20513
21812
  },
21813
+ Third: (args, compile2) => `${compile2(args[0])}[2]`,
20514
21814
  Mod: ([a, b], compile2) => {
20515
21815
  if (a === null || b === null) throw new Error("Mod: missing argument");
20516
21816
  const ca = compile2(a);
@@ -21579,6 +22879,14 @@ function gpuVec2(target) {
21579
22879
  function gpuVec3(target) {
21580
22880
  return target?.language === "wgsl" ? "vec3f" : "vec3";
21581
22881
  }
22882
+ function gpuNaN(target) {
22883
+ return target?.language === "wgsl" ? "bitcast<f32>(0x7fc00000u)" : "(0.0 / 0.0)";
22884
+ }
22885
+ function gpuConditional(cond, whenTrue, whenFalse, target) {
22886
+ if (target?.language === "wgsl")
22887
+ return `select(${whenFalse}, ${whenTrue}, ${cond})`;
22888
+ return `((${cond}) ? (${whenTrue}) : (${whenFalse}))`;
22889
+ }
21582
22890
  function readStringLiteral(expr) {
21583
22891
  if (!isString(expr)) return null;
21584
22892
  return expr.string?.toLowerCase() ?? null;
@@ -21696,7 +23004,7 @@ var GPU_FUNCTIONS = {
21696
23004
  const realFactors = args.filter((_, i) => i !== iIndex);
21697
23005
  const v2 = gpuVec2(target);
21698
23006
  if (realFactors.length === 0) return `${v2}(0.0, ${formatFloat(iScale)})`;
21699
- const factors = realFactors.map((f) => compile2(f));
23007
+ const factors = realFactors.map((f) => parenthesizeFactor(f, compile2(f)));
21700
23008
  if (iScale !== 1) factors.unshift(formatFloat(iScale));
21701
23009
  const imCode = foldTerms(factors, "1.0", "*");
21702
23010
  return `${v2}(0.0, ${imCode})`;
@@ -21705,7 +23013,7 @@ var GPU_FUNCTIONS = {
21705
23013
  const complexCodes = [];
21706
23014
  for (const a of args) {
21707
23015
  if (BaseCompiler.isComplexValued(a)) complexCodes.push(compile2(a));
21708
- else realCodes.push(compile2(a));
23016
+ else realCodes.push(parenthesizeFactor(a, compile2(a)));
21709
23017
  }
21710
23018
  const scalarCode = foldTerms(realCodes, "1.0", "*");
21711
23019
  let result = complexCodes[0];
@@ -21783,13 +23091,23 @@ var GPU_FUNCTIONS = {
21783
23091
  return `_gpu_ccos(${compile2(args[0])})`;
21784
23092
  return `cos(${compile2(args[0])})`;
21785
23093
  },
21786
- Degrees: "degrees",
23094
+ // CE's `Degrees` converts degrees→radians (Degrees(180) = π), which is
23095
+ // GLSL's `radians()`. GLSL's `degrees()` is the inverse (rad→deg).
23096
+ Degrees: "radians",
21787
23097
  Exp: (args, compile2) => {
21788
23098
  if (BaseCompiler.isComplexValued(args[0]))
21789
23099
  return `_gpu_cexp(${compile2(args[0])})`;
21790
23100
  return `exp(${compile2(args[0])})`;
21791
23101
  },
21792
23102
  Exp2: "exp2",
23103
+ // Component access — assumes the argument compiles to a vec2/vec3/vec4
23104
+ // (the common case for 2D/3D points). For 5+-element tuples that compile
23105
+ // to `float[N]` arrays, swizzle access is invalid GLSL and the shader
23106
+ // will fail to compile; that's an edge case `First`/`Second`/`Third`
23107
+ // aren't designed for. Vec swizzles are identical between GLSL and WGSL.
23108
+ First: (args, compile2) => `${compile2(args[0])}.x`,
23109
+ Second: (args, compile2) => `${compile2(args[0])}.y`,
23110
+ Third: (args, compile2) => `${compile2(args[0])}.z`,
21793
23111
  Floor: (args, compile2) => {
21794
23112
  if (BaseCompiler.isIntegerValued(args[0])) return compile2(args[0]);
21795
23113
  return `floor(${compile2(args[0])})`;
@@ -21804,6 +23122,43 @@ var GPU_FUNCTIONS = {
21804
23122
  Max: "max",
21805
23123
  Min: "min",
21806
23124
  Mix: "mix",
23125
+ // Control-flow forms — the base compiler's default emits a JS ternary and a
23126
+ // bare `NaN`, neither of which is valid GPU code (WGSL has no `?:`, and no
23127
+ // shader language has a `NaN` identifier). Emit `select(...)` for WGSL and a
23128
+ // language-appropriate NaN.
23129
+ If: (args, compile2, target) => {
23130
+ if (args.length !== 3) throw new Error("If: wrong number of arguments");
23131
+ return gpuConditional(
23132
+ compile2(args[0]),
23133
+ compile2(args[1]),
23134
+ compile2(args[2]),
23135
+ target
23136
+ );
23137
+ },
23138
+ When: (args, compile2, target) => {
23139
+ if (args.length !== 2)
23140
+ throw new Error("When: expected exactly 2 arguments (expr, cond)");
23141
+ if (isSymbol2(args[1], "True")) return `(${compile2(args[0])})`;
23142
+ if (isSymbol2(args[1], "False")) return gpuNaN(target);
23143
+ return gpuConditional(
23144
+ compile2(args[1]),
23145
+ compile2(args[0]),
23146
+ gpuNaN(target),
23147
+ target
23148
+ );
23149
+ },
23150
+ Which: (args, compile2, target) => {
23151
+ if (args.length < 2 || args.length % 2 !== 0)
23152
+ throw new Error("Which: expected condition/value pairs");
23153
+ const build = (i) => {
23154
+ if (i >= args.length) return gpuNaN(target);
23155
+ const cond = args[i];
23156
+ const val = args[i + 1];
23157
+ if (isSymbol2(cond, "True")) return `(${compile2(val)})`;
23158
+ return gpuConditional(compile2(cond), compile2(val), build(i + 2), target);
23159
+ };
23160
+ return build(0);
23161
+ },
21807
23162
  Power: (args, compile2, target) => {
21808
23163
  const base = args[0];
21809
23164
  const exp3 = args[1];
@@ -22267,6 +23622,39 @@ var GPU_FUNCTIONS = {
22267
23622
  // Sum/Product — unrolled or for-loop
22268
23623
  Sum: (args, compile2, target) => compileGPUSumProduct("Sum", args, compile2, target),
22269
23624
  Product: (args, compile2, target) => compileGPUSumProduct("Product", args, compile2, target),
23625
+ // Range — inline constant array literal (bounds must be compile-time constants)
23626
+ Range: (args, _compile, target) => {
23627
+ if (args.length < 2 || args.length > 3) {
23628
+ throw new Error(
23629
+ "Range: GPU compile expects 2 or 3 arguments (lo, hi, step?)"
23630
+ );
23631
+ }
23632
+ const lo = args[0].re;
23633
+ const hi = args[1].re;
23634
+ const step = args.length === 3 ? args[2].re : 1;
23635
+ if (!Number.isFinite(lo) || !Number.isFinite(hi) || !Number.isFinite(step)) {
23636
+ throw new Error(
23637
+ "Range: GPU compile requires constant numeric bounds (non-constant ranges must be materialized at JS host then uploaded as a uniform)"
23638
+ );
23639
+ }
23640
+ if (step === 0) throw new Error("Range: step cannot be zero");
23641
+ const count = Math.max(0, Math.floor((hi - lo) / step) + 1);
23642
+ if (count === 0) {
23643
+ throw new Error(
23644
+ "Range: empty range (lo > hi for positive step, or lo < hi for negative step)"
23645
+ );
23646
+ }
23647
+ if (count > 256) {
23648
+ throw new Error(
23649
+ `Range: GPU compile inlines ranges up to 256 elements (got ${count})`
23650
+ );
23651
+ }
23652
+ const values = [];
23653
+ for (let i = 0; i < count; i++) values.push(lo + i * step);
23654
+ const isWGSL = target.language === "wgsl";
23655
+ const arrayType = isWGSL ? `array<f32, ${count}>` : `float[${count}]`;
23656
+ return `${arrayType}(${values.map(formatGPUNumber).join(", ")})`;
23657
+ },
22270
23658
  // Loop — GPU for-loop (no IIFE, no let)
22271
23659
  Loop: (args, _compile, target) => {
22272
23660
  if (!args[0]) throw new Error("Loop: no body");
@@ -22295,6 +23683,134 @@ var GPU_FUNCTIONS = {
22295
23683
  ${bodyCode};
22296
23684
  }`;
22297
23685
  },
23686
+ // Statistical functions
23687
+ /**
23688
+ * GCD of two scalar arguments.
23689
+ *
23690
+ * Uses a preamble helper `_gpu_gcd` (Euclidean algorithm via `mod`).
23691
+ * Only two-argument form is supported in GPU targets.
23692
+ */
23693
+ GCD: (args, compile2) => {
23694
+ if (args.length < 2) throw new Error("GCD: need at least two arguments");
23695
+ if (args.length > 2)
23696
+ throw new Error("GCD: GPU target supports only two-argument GCD");
23697
+ const a = args[0];
23698
+ const b = args[1];
23699
+ if (a === null || b === null) throw new Error("GCD: missing argument");
23700
+ return `_gpu_gcd(${compile2(a)}, ${compile2(b)})`;
23701
+ },
23702
+ /**
23703
+ * Variance of a compile-time-known list.
23704
+ *
23705
+ * Accepts either a single `List(...)` argument or N scalar arguments.
23706
+ * Generates fully inline code: computes mean then sum of squared deviations,
23707
+ * divided by (N-1) for sample variance (matches JS `_SYS.variance`).
23708
+ */
23709
+ Variance: (args, compile2) => {
23710
+ let elems;
23711
+ if (args.length === 1 && isFunction2(args[0], "List")) {
23712
+ elems = args[0].ops;
23713
+ } else if (args.length >= 2) {
23714
+ elems = args;
23715
+ } else {
23716
+ throw new Error(
23717
+ "Variance: GPU target requires a List argument or at least 2 scalar arguments"
23718
+ );
23719
+ }
23720
+ const n = elems.length;
23721
+ if (n < 2) throw new Error("Variance: need at least 2 elements");
23722
+ const compiled = elems.map((e) => compile2(e));
23723
+ const sum = compiled.join(" + ");
23724
+ const mean2 = `((${sum}) / ${formatGPUNumber(n)})`;
23725
+ const sqDiffs = compiled.map((c) => `(${c} - ${mean2}) * (${c} - ${mean2})`).join(" + ");
23726
+ return `((${sqDiffs}) / ${formatGPUNumber(n - 1)})`;
23727
+ },
23728
+ /**
23729
+ * Median of a compile-time-known list.
23730
+ *
23731
+ * Accepts either a single `List(...)` argument or N scalar arguments.
23732
+ * For N ≤ 8: generates a fully unrolled inline sorting network followed by
23733
+ * a middle-element pick. For larger N, throws (too large to inline cleanly).
23734
+ *
23735
+ * The sorting network uses the "odd-even merge sort" comparator pattern
23736
+ * inlined as `min`/`max` calls — no GPU statements required.
23737
+ */
23738
+ Median: (args, compile2) => {
23739
+ let elems;
23740
+ if (args.length === 1 && isFunction2(args[0], "List")) {
23741
+ elems = args[0].ops;
23742
+ } else if (args.length >= 1) {
23743
+ elems = args;
23744
+ } else {
23745
+ throw new Error(
23746
+ "Median: GPU target requires a List argument or at least 1 scalar argument"
23747
+ );
23748
+ }
23749
+ const n = elems.length;
23750
+ if (n === 0) throw new Error("Median: empty list");
23751
+ if (n > 8) {
23752
+ throw new Error(
23753
+ `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.`
23754
+ );
23755
+ }
23756
+ const compiled = elems.map((e) => compile2(e));
23757
+ if (n === 1) return compiled[0];
23758
+ return `_gpu_median_${n}(${compiled.join(", ")})`;
23759
+ },
23760
+ /**
23761
+ * Deterministic pseudorandom for GPU.
23762
+ *
23763
+ * All emitted forms return a GLSL `float` (or WGSL `f32`) so the result
23764
+ * composes with surrounding float arithmetic without explicit casts. The
23765
+ * "integer-bound" forms return an integer-valued float (the result of
23766
+ * `floor`), matching the convention used by `Floor` and other ostensibly
23767
+ * integer-returning operators in this target.
23768
+ *
23769
+ * - 0 args (GLSL only): fall back to a fragment-coord-derived seed.
23770
+ * Only meaningful in fragment shaders (gl_FragCoord is FS-only).
23771
+ * - 0 args (WGSL): throws — WGSL has no built-in fragment coordinate;
23772
+ * caller must provide an explicit seed.
23773
+ * - 1 arg, real-typed: `_gpu_random(seed)` — deterministic float in [0, 1)
23774
+ * - 1 arg, integer-typed: `floor(_gpu_random(float(n)) * float(n))` —
23775
+ * integer-valued float in {0, 1, ..., n-1}. The seed is derived from
23776
+ * `n` itself, so the result is per-pixel-and-n deterministic in GLSL.
23777
+ * - 2 args (integer m, n): float in [m, n), seeded from gl_FragCoord.
23778
+ *
23779
+ * JS-side `Random` has matching semantics (see `library/core.ts`'s
23780
+ * polymorphic dispatch). JS↔GLSL parity is approximate — same seed yields
23781
+ * a similar value, not bit-identical, due to fp64 vs fp32 and platform
23782
+ * `sin` differences.
23783
+ */
23784
+ Random: (args, compile2, target) => {
23785
+ if (args.length === 0) {
23786
+ if (target.language === "wgsl") {
23787
+ throw new Error(
23788
+ "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."
23789
+ );
23790
+ }
23791
+ return "_gpu_random(gl_FragCoord.x + gl_FragCoord.y * 1024.0)";
23792
+ }
23793
+ if (args.length === 1) {
23794
+ const arg = args[0];
23795
+ if (BaseCompiler.isIntegerValued(arg)) {
23796
+ const compiled = compile2(arg);
23797
+ return `floor(_gpu_random(float(${compiled})) * float(${compiled}))`;
23798
+ }
23799
+ return `_gpu_random(${compile2(arg)})`;
23800
+ }
23801
+ if (args.length === 2) {
23802
+ if (target.language === "wgsl") {
23803
+ throw new Error(
23804
+ "Random(m, n): WGSL compile requires explicit seeding. Use a seeded variant or compute the integer range manually."
23805
+ );
23806
+ }
23807
+ const m = compile2(args[0]);
23808
+ const n = compile2(args[1]);
23809
+ const seed = "_gpu_random(gl_FragCoord.x + gl_FragCoord.y * 1024.0)";
23810
+ return `(float(${m}) + floor(${seed} * float((${n}) - (${m}))))`;
23811
+ }
23812
+ throw new Error("Random: GPU compile expects 0, 1, or 2 arguments");
23813
+ },
22298
23814
  // Function (lambda) — not supported in GPU
22299
23815
  Function: () => {
22300
23816
  throw new Error(
@@ -22330,7 +23846,7 @@ function compileGPUMatrix(args, compile2, vecFn, matFn, arrayFn) {
22330
23846
  }
22331
23847
  return compile2(body);
22332
23848
  }
22333
- var GPU_GAMMA_PREAMBLE = `
23849
+ var GPU_GAMMA_PREAMBLE_GLSL = `
22334
23850
  float _gpu_gamma(float z) {
22335
23851
  const float PI = 3.14159265358979;
22336
23852
  // For z < 0.5, use reflection formula with inlined Lanczos (non-recursive)
@@ -22362,7 +23878,37 @@ float _gpu_gammaln(float z) {
22362
23878
  + 1.0 / (1260.0 * z3 * z * z);
22363
23879
  }
22364
23880
  `;
22365
- var GPU_ERF_PREAMBLE = `
23881
+ var GPU_GAMMA_PREAMBLE_WGSL = `
23882
+ fn _gpu_gamma(z: f32) -> f32 {
23883
+ let PI = 3.14159265358979;
23884
+ var w = z;
23885
+ if (z < 0.5) { w = 1.0 - z; }
23886
+ w = w - 1.0;
23887
+ var x = 0.99999999999980993;
23888
+ x = x + 676.5203681218851 / (w + 1.0);
23889
+ x = x + -1259.1392167224028 / (w + 2.0);
23890
+ x = x + 771.32342877765313 / (w + 3.0);
23891
+ x = x + -176.61502916214059 / (w + 4.0);
23892
+ x = x + 12.507343278686905 / (w + 5.0);
23893
+ x = x + -0.13857109526572012 / (w + 6.0);
23894
+ x = x + 9.9843695780195716e-6 / (w + 7.0);
23895
+ x = x + 1.5056327351493116e-7 / (w + 8.0);
23896
+ let t = w + 7.5;
23897
+ let g = sqrt(2.0 * PI) * pow(t, w + 0.5) * exp(-t) * x;
23898
+ if (z < 0.5) { return PI / (sin(PI * z) * g); }
23899
+ return g;
23900
+ }
23901
+
23902
+ fn _gpu_gammaln(z: f32) -> f32 {
23903
+ let z3 = z * z * z;
23904
+ return z * log(z) - z - 0.5 * log(z)
23905
+ + 0.5 * log(2.0 * 3.14159265358979)
23906
+ + 1.0 / (12.0 * z)
23907
+ - 1.0 / (360.0 * z3)
23908
+ + 1.0 / (1260.0 * z3 * z * z);
23909
+ }
23910
+ `;
23911
+ var GPU_ERF_PREAMBLE_GLSL = `
22366
23912
  float _gpu_erf(float x) {
22367
23913
  float ax = abs(x);
22368
23914
  float t = 1.0 / (1.0 + 0.3275911 * ax);
@@ -22381,6 +23927,26 @@ float _gpu_erfinv(float x) {
22381
23927
  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);
22382
23928
  }
22383
23929
  `;
23930
+ var GPU_ERF_PREAMBLE_WGSL = `
23931
+ fn _gpu_erf(x: f32) -> f32 {
23932
+ let ax = abs(x);
23933
+ let t = 1.0 / (1.0 + 0.3275911 * ax);
23934
+ let y = ((((1.061405429 * t - 1.453152027) * t + 1.421413741) * t - 0.284496736) * t + 0.254829592) * t;
23935
+ let result = 1.0 - y * exp(-ax * ax);
23936
+ if (x < 0.0) { return -result; }
23937
+ return result;
23938
+ }
23939
+
23940
+ fn _gpu_erfinv(x: f32) -> f32 {
23941
+ let pi = 3.14159265358979;
23942
+ let x2 = x * x;
23943
+ let x3 = x * x2;
23944
+ let x5 = x3 * x2;
23945
+ let x7 = x5 * x2;
23946
+ let x9 = x7 * x2;
23947
+ 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);
23948
+ }
23949
+ `;
22384
23950
  var GPU_HEAVISIDE_PREAMBLE_GLSL = `
22385
23951
  float _gpu_heaviside(float x) {
22386
23952
  if (x < 0.0) return 0.0;
@@ -22894,6 +24460,212 @@ fn _fractal_julia(z_in: vec2f, c: vec2f, maxIter: i32) -> f32 {
22894
24460
  return 1.0;
22895
24461
  }
22896
24462
  `;
24463
+ var GPU_GCD_PREAMBLE_GLSL = `
24464
+ float _gpu_gcd(float a, float b) {
24465
+ a = abs(a); b = abs(b);
24466
+ for (int i = 0; i < 32; i++) {
24467
+ if (b < 0.5) break;
24468
+ float t = mod(a, b);
24469
+ a = b;
24470
+ b = t;
24471
+ }
24472
+ return a;
24473
+ }
24474
+ `;
24475
+ var GPU_GCD_PREAMBLE_WGSL = `
24476
+ fn _gpu_gcd(a_in: f32, b_in: f32) -> f32 {
24477
+ var a = abs(a_in); var b = abs(b_in);
24478
+ for (var i: i32 = 0; i < 32; i++) {
24479
+ if (b < 0.5) { break; }
24480
+ let t = a % b;
24481
+ a = b;
24482
+ b = t;
24483
+ }
24484
+ return a;
24485
+ }
24486
+ `;
24487
+ var GPU_RANDOM_PREAMBLE_GLSL = `
24488
+ // Deterministic pseudorandom in [0, 1) from a float seed.
24489
+ // Standard fract-sin hash; reproducible across runs for the same seed.
24490
+ // Note: this hash exhibits visible banding near seed \u2248 k\u03C0 for integer k.
24491
+ // For high-quality shader random, callers should use a more robust hash
24492
+ // (e.g. PCG or xxHash) and pre-seed it appropriately.
24493
+ float _gpu_random(float seed) {
24494
+ return fract(sin(seed * 12.9898) * 43758.5453);
24495
+ }
24496
+ `;
24497
+ var GPU_RANDOM_PREAMBLE_WGSL = `
24498
+ // Deterministic pseudorandom in [0, 1) from a float seed.
24499
+ // Standard fract-sin hash; reproducible across runs for the same seed.
24500
+ // Note: this hash exhibits visible banding near seed \u2248 k\u03C0 for integer k.
24501
+ // For high-quality shader random, callers should use a more robust hash
24502
+ // (e.g. PCG or xxHash) and pre-seed it appropriately.
24503
+ fn _gpu_random(seed: f32) -> f32 {
24504
+ return fract(sin(seed * 12.9898) * 43758.5453);
24505
+ }
24506
+ `;
24507
+ var GPU_MEDIAN_PREAMBLE_GLSL = `
24508
+ float _gpu_median_2(float a, float b) {
24509
+ return (a + b) * 0.5;
24510
+ }
24511
+ float _gpu_median_3(float a, float b, float c) {
24512
+ return max(min(a, b), min(max(a, b), c));
24513
+ }
24514
+ float _gpu_median_4(float a, float b, float c, float d) {
24515
+ float lo = max(min(a, b), min(c, d));
24516
+ float hi = min(max(a, b), max(c, d));
24517
+ return (lo + hi) * 0.5;
24518
+ }
24519
+ float _gpu_median_5(float a, float b, float c, float d, float e) {
24520
+ // 9-comparator Bose-Nelson sort; v2 holds the median.
24521
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e;
24522
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
24523
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24524
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
24525
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
24526
+ t=min(v0,v3); v3=max(v0,v3); v0=t;
24527
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
24528
+ t=min(v1,v4); v4=max(v1,v4); v1=t;
24529
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
24530
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
24531
+ return v2;
24532
+ }
24533
+ float _gpu_median_6(float a, float b, float c, float d, float e, float f) {
24534
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f;
24535
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
24536
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
24537
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
24538
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
24539
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
24540
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
24541
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
24542
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
24543
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
24544
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
24545
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24546
+ return (v2 + v3) * 0.5;
24547
+ }
24548
+ float _gpu_median_7(float a, float b, float c, float d, float e, float f, float g) {
24549
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f,v6=g;
24550
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
24551
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
24552
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
24553
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
24554
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
24555
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
24556
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
24557
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
24558
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
24559
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
24560
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
24561
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
24562
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24563
+ return v3;
24564
+ }
24565
+ float _gpu_median_8(float a, float b, float c, float d, float e, float f, float g, float h) {
24566
+ float t; float v0=a,v1=b,v2=c,v3=d,v4=e,v5=f,v6=g,v7=h;
24567
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
24568
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
24569
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
24570
+ t=min(v6,v7); v7=max(v6,v7); v6=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(v4,v6); v6=max(v4,v6); v4=t;
24574
+ t=min(v5,v7); v7=max(v5,v7); v5=t;
24575
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
24576
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
24577
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
24578
+ t=min(v3,v7); v7=max(v3,v7); v3=t;
24579
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
24580
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24581
+ t=min(v5,v6); v6=max(v5,v6); v5=t;
24582
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
24583
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
24584
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24585
+ return (v3 + v4) * 0.5;
24586
+ }
24587
+ `;
24588
+ var GPU_MEDIAN_PREAMBLE_WGSL = `
24589
+ fn _gpu_median_2(a: f32, b: f32) -> f32 {
24590
+ return (a + b) * 0.5;
24591
+ }
24592
+ fn _gpu_median_3(a: f32, b: f32, c: f32) -> f32 {
24593
+ return max(min(a, b), min(max(a, b), c));
24594
+ }
24595
+ fn _gpu_median_4(a: f32, b: f32, c: f32, d: f32) -> f32 {
24596
+ let lo = max(min(a, b), min(c, d));
24597
+ let hi = min(max(a, b), max(c, d));
24598
+ return (lo + hi) * 0.5;
24599
+ }
24600
+ fn _gpu_median_5(a: f32, b: f32, c: f32, d: f32, e: f32) -> f32 {
24601
+ // 9-comparator Bose-Nelson sort; v2 holds the median.
24602
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var t: f32;
24603
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
24604
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24605
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
24606
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
24607
+ t=min(v0,v3); v3=max(v0,v3); v0=t;
24608
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
24609
+ t=min(v1,v4); v4=max(v1,v4); v1=t;
24610
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
24611
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
24612
+ return v2;
24613
+ }
24614
+ fn _gpu_median_6(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) -> f32 {
24615
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var v5=f; var t: f32;
24616
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
24617
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
24618
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
24619
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
24620
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
24621
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
24622
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
24623
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
24624
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
24625
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
24626
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24627
+ return (v2 + v3) * 0.5;
24628
+ }
24629
+ fn _gpu_median_7(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32, g: f32) -> f32 {
24630
+ var v0=a; var v1=b; var v2=c; var v3=d; var v4=e; var v5=f; var v6=g; var t: f32;
24631
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
24632
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
24633
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
24634
+ t=min(v0,v2); v2=max(v0,v2); v0=t;
24635
+ t=min(v1,v3); v3=max(v1,v3); v1=t;
24636
+ t=min(v4,v6); v6=max(v4,v6); v4=t;
24637
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
24638
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
24639
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
24640
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
24641
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
24642
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
24643
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24644
+ return v3;
24645
+ }
24646
+ fn _gpu_median_8(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32, g: f32, h: f32) -> f32 {
24647
+ 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;
24648
+ t=min(v0,v1); v1=max(v0,v1); v0=t;
24649
+ t=min(v2,v3); v3=max(v2,v3); v2=t;
24650
+ t=min(v4,v5); v5=max(v4,v5); v4=t;
24651
+ t=min(v6,v7); v7=max(v6,v7); v6=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(v4,v6); v6=max(v4,v6); v4=t;
24655
+ t=min(v5,v7); v7=max(v5,v7); v5=t;
24656
+ t=min(v0,v4); v4=max(v0,v4); v0=t;
24657
+ t=min(v1,v5); v5=max(v1,v5); v1=t;
24658
+ t=min(v2,v6); v6=max(v2,v6); v2=t;
24659
+ t=min(v3,v7); v7=max(v3,v7); v3=t;
24660
+ t=min(v1,v2); v2=max(v1,v2); v1=t;
24661
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24662
+ t=min(v5,v6); v6=max(v5,v6); v5=t;
24663
+ t=min(v3,v5); v5=max(v3,v5); v3=t;
24664
+ t=min(v2,v4); v4=max(v2,v4); v2=t;
24665
+ t=min(v3,v4); v4=max(v3,v4); v3=t;
24666
+ return (v3 + v4) * 0.5;
24667
+ }
24668
+ `;
22897
24669
  var GPU_COLOR_PREAMBLE_GLSL = `
22898
24670
  float _gpu_srgb_to_linear(float c) {
22899
24671
  if (c <= 0.04045) return c / 12.92;
@@ -23554,8 +25326,10 @@ var GPUShaderTarget = class {
23554
25326
  };
23555
25327
  let preamble = "";
23556
25328
  preamble += buildComplexPreamble(code, this.languageId);
23557
- if (code.includes("_gpu_gamma")) preamble += GPU_GAMMA_PREAMBLE;
23558
- if (code.includes("_gpu_erf")) preamble += GPU_ERF_PREAMBLE;
25329
+ if (code.includes("_gpu_gamma"))
25330
+ preamble += this.languageId === "wgsl" ? GPU_GAMMA_PREAMBLE_WGSL : GPU_GAMMA_PREAMBLE_GLSL;
25331
+ if (code.includes("_gpu_erf"))
25332
+ preamble += this.languageId === "wgsl" ? GPU_ERF_PREAMBLE_WGSL : GPU_ERF_PREAMBLE_GLSL;
23559
25333
  if (code.includes("_gpu_heaviside"))
23560
25334
  preamble += this.languageId === "wgsl" ? GPU_HEAVISIDE_PREAMBLE_WGSL : GPU_HEAVISIDE_PREAMBLE_GLSL;
23561
25335
  if (code.includes("_gpu_sinc"))
@@ -23571,6 +25345,12 @@ var GPUShaderTarget = class {
23571
25345
  if (code.includes("_fractal_")) {
23572
25346
  preamble += this.languageId === "wgsl" ? GPU_FRACTAL_PREAMBLE_WGSL : GPU_FRACTAL_PREAMBLE_GLSL;
23573
25347
  }
25348
+ if (code.includes("_gpu_random"))
25349
+ preamble += this.languageId === "wgsl" ? GPU_RANDOM_PREAMBLE_WGSL : GPU_RANDOM_PREAMBLE_GLSL;
25350
+ if (code.includes("_gpu_gcd"))
25351
+ preamble += this.languageId === "wgsl" ? GPU_GCD_PREAMBLE_WGSL : GPU_GCD_PREAMBLE_GLSL;
25352
+ if (code.includes("_gpu_median_"))
25353
+ preamble += this.languageId === "wgsl" ? GPU_MEDIAN_PREAMBLE_WGSL : GPU_MEDIAN_PREAMBLE_GLSL;
23574
25354
  if (code.includes("_gpu_srgb_to") || code.includes("_gpu_oklab") || code.includes("_gpu_oklch") || code.includes("_gpu_color_mix") || code.includes("_gpu_apca")) {
23575
25355
  preamble += this.languageId === "wgsl" ? GPU_COLOR_PREAMBLE_WGSL : GPU_COLOR_PREAMBLE_GLSL;
23576
25356
  }
@@ -24335,9 +26115,18 @@ function negate(x) {
24335
26115
  return ok({ lo: -xVal.hi, hi: -xVal.lo });
24336
26116
  }
24337
26117
  function _mul(a, b) {
24338
- const products = [a.lo * b.lo, a.lo * b.hi, a.hi * b.lo, a.hi * b.hi];
26118
+ const products = [
26119
+ _prod(a.lo, b.lo),
26120
+ _prod(a.lo, b.hi),
26121
+ _prod(a.hi, b.lo),
26122
+ _prod(a.hi, b.hi)
26123
+ ];
24339
26124
  return { lo: Math.min(...products), hi: Math.max(...products) };
24340
26125
  }
26126
+ function _prod(x, y) {
26127
+ if (x === 0 || y === 0) return 0;
26128
+ return x * y;
26129
+ }
24341
26130
  function mul3(a, b) {
24342
26131
  const unwrapped = unwrapOrPropagate(a, b);
24343
26132
  if (!Array.isArray(unwrapped)) return unwrapped;
@@ -24671,6 +26460,7 @@ function mod(a, b) {
24671
26460
  const period = Math.abs(
24672
26461
  bVal.lo === bVal.hi ? bVal.lo : Math.max(Math.abs(bVal.lo), Math.abs(bVal.hi))
24673
26462
  );
26463
+ const divisorNegative = bVal.hi < 0;
24674
26464
  const flo = Math.floor(aVal.lo / period);
24675
26465
  const fhi = Math.floor(aVal.hi / period);
24676
26466
  if (flo !== fhi) {
@@ -24678,6 +26468,11 @@ function mod(a, b) {
24678
26468
  }
24679
26469
  const modLo = aVal.lo - period * flo;
24680
26470
  const modHi = aVal.hi - period * flo;
26471
+ if (divisorNegative) {
26472
+ if (modLo === 0)
26473
+ return { kind: "singular", at: aVal.lo, continuity: "right" };
26474
+ return ok({ lo: modLo - period, hi: modHi - period });
26475
+ }
24681
26476
  return ok({ lo: Math.min(modLo, modHi), hi: Math.max(modLo, modHi) });
24682
26477
  }
24683
26478
  function remainder(a, b) {
@@ -24709,6 +26504,23 @@ function gamma2(x) {
24709
26504
  const [xVal] = unwrapped;
24710
26505
  return _gamma(xVal);
24711
26506
  }
26507
+ var GAMMA_NEG_EXTREMA_X = [
26508
+ -0.504083008264455,
26509
+ -1.573498473162391,
26510
+ -2.610720868444145,
26511
+ -3.635293366436901,
26512
+ -4.653163765628266,
26513
+ -5.667162441556885,
26514
+ -6.678418213073426,
26515
+ -7.687788325031709,
26516
+ -8.695764163640956,
26517
+ -9.702672540001863
26518
+ ];
26519
+ function gammaNegStripExtremum(lo) {
26520
+ const n = Math.floor(lo);
26521
+ const idx = -n - 1;
26522
+ return idx >= 0 && idx < GAMMA_NEG_EXTREMA_X.length ? GAMMA_NEG_EXTREMA_X[idx] : null;
26523
+ }
24712
26524
  function _gamma(x) {
24713
26525
  if (x.hi >= 0 && x.lo <= 0) {
24714
26526
  return { kind: "singular", at: 0 };
@@ -24721,7 +26533,21 @@ function _gamma(x) {
24721
26533
  }
24722
26534
  const gLo = gamma(x.lo);
24723
26535
  const gHi = gamma(x.hi);
24724
- return ok({ lo: Math.min(gLo, gHi), hi: Math.max(gLo, gHi) });
26536
+ let lo = Math.min(gLo, gHi);
26537
+ let hi = Math.max(gLo, gHi);
26538
+ const xStar = gammaNegStripExtremum(x.lo);
26539
+ if (xStar !== null) {
26540
+ if (xStar >= x.lo && xStar <= x.hi) {
26541
+ const g = gamma(xStar);
26542
+ lo = Math.min(lo, g);
26543
+ hi = Math.max(hi, g);
26544
+ }
26545
+ } else {
26546
+ const stripEven = Math.floor(x.lo) % 2 === 0;
26547
+ if (stripEven) lo = Math.min(lo, 0);
26548
+ else hi = Math.max(hi, 0);
26549
+ }
26550
+ return ok({ lo, hi });
24725
26551
  }
24726
26552
  if (x.lo >= GAMMA_MIN_X) {
24727
26553
  return ok({ lo: gamma(x.lo), hi: gamma(x.hi) });
@@ -24752,7 +26578,15 @@ function _gammaln(x) {
24752
26578
  }
24753
26579
  const gLo = gammaln(x.lo);
24754
26580
  const gHi = gammaln(x.hi);
24755
- return ok({ lo: Math.min(gLo, gHi), hi: Math.max(gLo, gHi) });
26581
+ let lo = Math.min(gLo, gHi);
26582
+ const hi = Math.max(gLo, gHi);
26583
+ const xStar = gammaNegStripExtremum(x.lo);
26584
+ if (xStar !== null) {
26585
+ if (xStar >= x.lo && xStar <= x.hi) lo = Math.min(lo, gammaln(xStar));
26586
+ } else {
26587
+ lo = -Infinity;
26588
+ }
26589
+ return ok({ lo, hi });
24756
26590
  }
24757
26591
  return ok({ lo: gammaln(x.lo), hi: gammaln(x.hi) });
24758
26592
  }
@@ -24778,6 +26612,33 @@ function factorial22(x) {
24778
26612
  return ok({ lo: Math.min(fLo, fHi), hi: Math.max(fLo, fHi) });
24779
26613
  return ok({ lo: fLo, hi: fHi });
24780
26614
  }
26615
+ var MAX_INT_ENUM_POINTS = 4096;
26616
+ function integerPoints(lo, hi, cap) {
26617
+ const a = Math.round(lo);
26618
+ const b = Math.round(hi);
26619
+ if (!Number.isFinite(a) || !Number.isFinite(b)) return null;
26620
+ if (b - a + 1 > cap) return null;
26621
+ const out = [];
26622
+ for (let i = a; i <= b; i++) out.push(i);
26623
+ return out;
26624
+ }
26625
+ function enumerateInteger2(a, b, f) {
26626
+ const xs = integerPoints(a.lo, a.hi, MAX_INT_ENUM_POINTS);
26627
+ const ys = integerPoints(b.lo, b.hi, MAX_INT_ENUM_POINTS);
26628
+ if (!xs || !ys || xs.length * ys.length > MAX_INT_ENUM_POINTS) return null;
26629
+ let lo = Infinity;
26630
+ let hi = -Infinity;
26631
+ for (const x of xs)
26632
+ for (const y of ys) {
26633
+ const v = f(x, y);
26634
+ if (Number.isFinite(v)) {
26635
+ if (v < lo) lo = v;
26636
+ if (v > hi) hi = v;
26637
+ }
26638
+ }
26639
+ if (lo === Infinity) return null;
26640
+ return ok({ lo, hi });
26641
+ }
24781
26642
  function binomial(n, k) {
24782
26643
  const uN = unwrapOrPropagate(n);
24783
26644
  if (!Array.isArray(uN)) return uN;
@@ -24785,13 +26646,10 @@ function binomial(n, k) {
24785
26646
  if (!Array.isArray(uK)) return uK;
24786
26647
  const [nVal] = uN;
24787
26648
  const [kVal] = uK;
24788
- const vals = [
24789
- choose(Math.round(nVal.lo), Math.round(kVal.lo)),
24790
- choose(Math.round(nVal.lo), Math.round(kVal.hi)),
24791
- choose(Math.round(nVal.hi), Math.round(kVal.lo)),
24792
- choose(Math.round(nVal.hi), Math.round(kVal.hi))
24793
- ];
24794
- return ok({ lo: Math.min(...vals), hi: Math.max(...vals) });
26649
+ const enumerated = enumerateInteger2(nVal, kVal, choose);
26650
+ if (enumerated) return enumerated;
26651
+ const nMax = Math.round(nVal.hi);
26652
+ return ok({ lo: 0, hi: choose(nMax, Math.floor(nMax / 2)) });
24795
26653
  }
24796
26654
  function gcd3(a, b) {
24797
26655
  const uA = unwrapOrPropagate(a);
@@ -24800,13 +26658,15 @@ function gcd3(a, b) {
24800
26658
  if (!Array.isArray(uB)) return uB;
24801
26659
  const [aVal] = uA;
24802
26660
  const [bVal] = uB;
24803
- const vals = [
24804
- gcd(Math.round(aVal.lo), Math.round(bVal.lo)),
24805
- gcd(Math.round(aVal.lo), Math.round(bVal.hi)),
24806
- gcd(Math.round(aVal.hi), Math.round(bVal.lo)),
24807
- gcd(Math.round(aVal.hi), Math.round(bVal.hi))
24808
- ];
24809
- return ok({ lo: Math.min(...vals), hi: Math.max(...vals) });
26661
+ const enumerated = enumerateInteger2(aVal, bVal, gcd);
26662
+ if (enumerated) return enumerated;
26663
+ const m = Math.max(
26664
+ Math.abs(Math.round(aVal.lo)),
26665
+ Math.abs(Math.round(aVal.hi)),
26666
+ Math.abs(Math.round(bVal.lo)),
26667
+ Math.abs(Math.round(bVal.hi))
26668
+ );
26669
+ return ok({ lo: 0, hi: m });
24810
26670
  }
24811
26671
  function lcm3(a, b) {
24812
26672
  const uA = unwrapOrPropagate(a);
@@ -24815,13 +26675,11 @@ function lcm3(a, b) {
24815
26675
  if (!Array.isArray(uB)) return uB;
24816
26676
  const [aVal] = uA;
24817
26677
  const [bVal] = uB;
24818
- const vals = [
24819
- lcm(Math.round(aVal.lo), Math.round(bVal.lo)),
24820
- lcm(Math.round(aVal.lo), Math.round(bVal.hi)),
24821
- lcm(Math.round(aVal.hi), Math.round(bVal.lo)),
24822
- lcm(Math.round(aVal.hi), Math.round(bVal.hi))
24823
- ];
24824
- return ok({ lo: Math.min(...vals), hi: Math.max(...vals) });
26678
+ const enumerated = enumerateInteger2(aVal, bVal, lcm);
26679
+ if (enumerated) return enumerated;
26680
+ const ma = Math.max(Math.abs(Math.round(aVal.lo)), Math.abs(Math.round(aVal.hi)));
26681
+ const mb = Math.max(Math.abs(Math.round(bVal.lo)), Math.abs(Math.round(bVal.hi)));
26682
+ return ok({ lo: 0, hi: ma * mb });
24825
26683
  }
24826
26684
  function chop2(x) {
24827
26685
  const unwrapped = unwrapOrPropagate(x);
@@ -25213,7 +27071,6 @@ var SINC_EXTREMA = [
25213
27071
  29.8116,
25214
27072
  32.95639
25215
27073
  ];
25216
- var SINC_GLOBAL_LO = -0.21724;
25217
27074
  function sinc2(x) {
25218
27075
  const unwrapped = unwrapOrPropagate(x);
25219
27076
  if (!Array.isArray(unwrapped)) return unwrapped;
@@ -25234,8 +27091,14 @@ function sinc2(x) {
25234
27091
  if (e >= xVal.lo && e <= xVal.hi) update(sincVal(e));
25235
27092
  if (-e >= xVal.lo && -e <= xVal.hi) update(sincVal(-e));
25236
27093
  }
25237
- if (Math.abs(xVal.lo) > lastExtremum || Math.abs(xVal.hi) > lastExtremum) {
25238
- update(SINC_GLOBAL_LO);
27094
+ let minBeyondAbs = Infinity;
27095
+ if (xVal.hi > lastExtremum)
27096
+ minBeyondAbs = Math.min(minBeyondAbs, Math.max(xVal.lo, lastExtremum));
27097
+ if (xVal.lo < -lastExtremum)
27098
+ minBeyondAbs = Math.min(minBeyondAbs, -Math.min(xVal.hi, -lastExtremum));
27099
+ if (Number.isFinite(minBeyondAbs) && minBeyondAbs > 0) {
27100
+ update(1 / minBeyondAbs);
27101
+ update(-1 / minBeyondAbs);
25239
27102
  }
25240
27103
  return ok({ lo, hi });
25241
27104
  }
@@ -25261,8 +27124,21 @@ function fresnelS2(x) {
25261
27124
  if (e >= xVal.lo && e <= xVal.hi) update(fresnelS(e));
25262
27125
  if (-e >= xVal.lo && -e <= xVal.hi) update(fresnelS(-e));
25263
27126
  }
27127
+ fresnelConvergenceBound(xVal, FRESNEL_S_EXTREMA, fresnelS, update);
25264
27128
  return ok({ lo, hi });
25265
27129
  }
27130
+ function fresnelConvergenceBound(xVal, extrema, scalar, update) {
27131
+ const lastE = extrema[extrema.length - 1];
27132
+ const amp = Math.abs(scalar(lastE) - 0.5);
27133
+ if (xVal.hi > lastE) {
27134
+ update(0.5 + amp);
27135
+ update(0.5 - amp);
27136
+ }
27137
+ if (xVal.lo < -lastE) {
27138
+ update(-0.5 - amp);
27139
+ update(-0.5 + amp);
27140
+ }
27141
+ }
25266
27142
  function fresnelC2(x) {
25267
27143
  const unwrapped = unwrapOrPropagate(x);
25268
27144
  if (!Array.isArray(unwrapped)) return unwrapped;
@@ -25279,6 +27155,7 @@ function fresnelC2(x) {
25279
27155
  if (e >= xVal.lo && e <= xVal.hi) update(fresnelC(e));
25280
27156
  if (-e >= xVal.lo && -e <= xVal.hi) update(fresnelC(-e));
25281
27157
  }
27158
+ fresnelConvergenceBound(xVal, FRESNEL_C_EXTREMA, fresnelC, update);
25282
27159
  return ok({ lo, hi });
25283
27160
  }
25284
27161
 
@@ -25386,11 +27263,9 @@ function clamp(x, lo, hi) {
25386
27263
  const unwrapped = unwrapOrPropagate(x, lo, hi);
25387
27264
  if (!Array.isArray(unwrapped)) return unwrapped;
25388
27265
  const [xVal, loVal, hiVal] = unwrapped;
25389
- const resultLo = Math.max(xVal.lo, loVal.lo);
25390
- const resultHi = Math.min(xVal.hi, hiVal.hi);
25391
- if (resultLo > resultHi) {
25392
- return { kind: "empty" };
25393
- }
27266
+ const lowered = { lo: Math.max(xVal.lo, loVal.lo), hi: Math.max(xVal.hi, loVal.hi) };
27267
+ const resultLo = Math.min(lowered.lo, hiVal.lo);
27268
+ const resultHi = Math.min(lowered.hi, hiVal.hi);
25394
27269
  return { kind: "interval", value: { lo: resultLo, hi: resultHi } };
25395
27270
  }
25396
27271
 
@@ -25723,7 +27598,7 @@ function extractIntervalLimits(limitsExpr) {
25723
27598
  function compileIntervalBound(expr, numVal, target) {
25724
27599
  if (numVal !== void 0) return String(numVal);
25725
27600
  const compiled = BaseCompiler.compile(expr, target);
25726
- return `Math.floor((${compiled}).hi)`;
27601
+ return `Math.floor(((_b) => (_b && _b.value ? _b.value.hi : _b.hi))(${compiled}))`;
25727
27602
  }
25728
27603
  function compileIntervalSumProduct(kind, args, _compile, target) {
25729
27604
  if (!args[0]) throw new Error(`${kind}: no body`);
@@ -25909,7 +27784,7 @@ function compileToIntervalTarget(expr, target) {
25909
27784
  }
25910
27785
 
25911
27786
  // src/compile.ts
25912
- var version = "0.57.0";
27787
+ var version = "0.59.0";
25913
27788
  export {
25914
27789
  BaseCompiler,
25915
27790
  GLSLTarget,