1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum Cause {
10 UserInput,
11 Domain,
12 Unsupported,
13 Resource,
14 Internal,
15}
16
17pub struct ErrorSpec {
18 pub code: &'static str,
19 pub class: &'static str,
20 pub cause: Cause,
21 pub remediation: Option<&'static str>,
22}
23
24pub const REGISTRY: &[ErrorSpec] = &[
25 ErrorSpec { code: "E-POLY-001", class: "ConversionError", cause: Cause::UserInput, remediation: Some("remove the unsupported symbol, or declare it as a parameter") },
27 ErrorSpec { code: "E-POLY-002", class: "ConversionError", cause: Cause::UserInput, remediation: Some("all coefficients must be rational integers; rationalize or substitute") },
28 ErrorSpec { code: "E-POLY-003", class: "ConversionError", cause: Cause::UserInput, remediation: Some("only non-negative integer exponents are supported in poly_normal") },
29 ErrorSpec { code: "E-POLY-004", class: "ConversionError", cause: Cause::UserInput, remediation: Some("reduce the degree or switch to a sparse representation") },
30 ErrorSpec { code: "E-POLY-005", class: "ConversionError", cause: Cause::UserInput, remediation: Some("substitute a concrete integer for the exponent before calling poly_normal") },
31 ErrorSpec { code: "E-POLY-006", class: "ConversionError", cause: Cause::Unsupported, remediation: Some("only polynomial expressions are supported; remove transcendental functions") },
32 ErrorSpec { code: "E-POLY-007", class: "ConversionError", cause: Cause::Domain, remediation: Some("ensure the denominator is non-zero before converting") },
33 ErrorSpec { code: "E-POLY-008", class: "FactorError", cause: Cause::UserInput, remediation: Some("factorization is only defined for non-zero polynomials") },
34 ErrorSpec { code: "E-POLY-009", class: "FactorError", cause: Cause::UserInput, remediation: Some("use a modulus ≥ 2 that fits in a machine word (FLINT nmod)") },
35 ErrorSpec { code: "E-POLY-010", class: "FactorError", cause: Cause::Internal, remediation: Some("report the polynomial as a minimal failing example") },
36 ErrorSpec { code: "E-DIFF-001", class: "DiffError", cause: Cause::Unsupported, remediation: Some("register the function in PrimitiveRegistry, or use diff_forward with a custom rule") },
38 ErrorSpec { code: "E-DIFF-002", class: "DiffError", cause: Cause::UserInput, remediation: Some("symbolic exponents require the chain rule; use diff_forward for non-integer powers") },
39 ErrorSpec { code: "E-DIFF-003", class: "DiffError", cause: Cause::Unsupported, remediation: Some("register the function in PrimitiveRegistry with diff_forward implemented") },
40 ErrorSpec { code: "E-DIFF-004", class: "DiffError", cause: Cause::UserInput, remediation: Some("substitute concrete values first; diff_forward requires integer exponents") },
41 ErrorSpec { code: "E-SERIES-001", class: "SeriesError", cause: Cause::Unsupported, remediation: Some("ensure all functions are registered primitives with differentiation rules") },
43 ErrorSpec { code: "E-SERIES-002", class: "SeriesError", cause: Cause::UserInput, remediation: Some("pass order >= 1 (exclusive truncation degree in x)") },
44 ErrorSpec { code: "E-INT-001", class: "IntegrationError", cause: Cause::Unsupported, remediation: Some("use a numeric integrator for arbitrary functions") },
46 ErrorSpec { code: "E-INT-002", class: "IntegrationError", cause: Cause::Domain, remediation: None },
47 ErrorSpec { code: "E-INT-003", class: "IntegrationError", cause: Cause::Unsupported, remediation: Some("v1.1 supports sqrt(P(x)) only; higher-degree radicals planned for v2.0") },
48 ErrorSpec { code: "E-INT-004", class: "IntegrationError", cause: Cause::Domain, remediation: Some("no elementary antiderivative exists; use a numeric integrator or elliptic-integral library") },
49 ErrorSpec { code: "E-MAT-001", class: "MatrixError", cause: Cause::UserInput, remediation: Some("check that row/column counts agree") },
51 ErrorSpec { code: "E-MAT-002", class: "MatrixError", cause: Cause::UserInput, remediation: Some("use pseudo-inverse for rectangular matrices") },
52 ErrorSpec { code: "E-MAT-003", class: "MatrixError", cause: Cause::Domain, remediation: Some("check for linear dependence in the rows/columns") },
53 ErrorSpec { code: "E-EIGEN-001", class: "EigenError", cause: Cause::UserInput, remediation: Some("pass a square n×n matrix") },
55 ErrorSpec { code: "E-EIGEN-002", class: "EigenError", cause: Cause::UserInput, remediation: Some("ensure det(λI−M) is a ℤ-polynomial in the fresh λ variable") },
56 ErrorSpec { code: "E-EIGEN-003", class: "EigenError", cause: Cause::Internal, remediation: Some("report the polynomial as a minimal failing example") },
57 ErrorSpec { code: "E-EIGEN-004", class: "EigenError", cause: Cause::Unsupported, remediation: Some("irreducible characteristic factors of degree > 2 require a future algebraic-number extension") },
58 ErrorSpec { code: "E-EIGEN-005", class: "EigenError", cause: Cause::Domain, remediation: Some("the matrix is defective or the eigenbasis is incomplete") },
59 ErrorSpec { code: "E-EIGEN-006", class: "EigenError", cause: Cause::Unsupported, remediation: Some("nullspace elimination failed; try a purely rational or ℚ(i) spectrum") },
60 ErrorSpec { code: "E-EIGEN-007", class: "EigenError", cause: Cause::Domain, remediation: Some("eigenvector matrix is singular; check multiplicities") },
61 ErrorSpec { code: "E-ODE-001", class: "OdeError", cause: Cause::UserInput, remediation: Some("number of state variables must equal number of RHS expressions") },
63 ErrorSpec { code: "E-ODE-002", class: "OdeError", cause: Cause::UserInput, remediation: Some("use lower_to_first_order() before passing to a solver") },
64 ErrorSpec { code: "E-ODE-003", class: "OdeError", cause: Cause::Unsupported, remediation: Some("check differentiability of all functions in the system") },
65 ErrorSpec { code: "E-DAE-001", class: "DaeError", cause: Cause::Unsupported, remediation: Some("ensure all functions are differentiable before calling pantelides()") },
67 ErrorSpec { code: "E-DAE-002", class: "DaeError", cause: Cause::UserInput, remediation: Some("DAE index exceeds depth-10 limit; reformulate the model") },
68 ErrorSpec { code: "E-DAE-003", class: "DaeError", cause: Cause::UserInput, remediation: Some("check constraint count against variable count") },
69 ErrorSpec { code: "E-DIFFALG-001", class: "DiffAlgError", cause: Cause::Unsupported, remediation: Some("ensure the DAE is polynomial in its state and derivative symbols") },
71 ErrorSpec { code: "E-DIFFALG-002", class: "DiffAlgError", cause: Cause::UserInput, remediation: Some("declare all jet variables; remove transcendental functions") },
72 ErrorSpec { code: "E-SOLVE-001", class: "SolverError", cause: Cause::UserInput, remediation: Some("ensure all equations are polynomial in the declared variables") },
73 ErrorSpec { code: "E-SOLVE-002", class: "SolverError", cause: Cause::Unsupported, remediation: Some("only degree ≤ 2 univariate solving is implemented; Gröbner basis is still returned") },
74 ErrorSpec { code: "E-SOLVE-003", class: "SolverError", cause: Cause::UserInput, remediation: Some("provide one equation per variable") },
75 ErrorSpec { code: "E-SOLVE-010", class: "SolverError", cause: Cause::Resource, remediation: Some("check GPU availability; pass device_id=None to fall back to CPU") },
76 ErrorSpec { code: "E-SOLVE-011", class: "SolverError", cause: Cause::Resource, remediation: Some("CRT reconstruction failed; try adding more equations or use CPU path") },
77 ErrorSpec { code: "E-HOMOTOPY-002", class: "HomotopyError", cause: Cause::Unsupported, remediation: Some("raise HomotopyOpts.max_bezout_paths or use mixed-volume continuation for deficient systems") },
79 ErrorSpec { code: "E-HOMOTOPY-003", class: "HomotopyError", cause: Cause::Resource, remediation: Some("try HomotopyOpts.gamma_angle_seed or rescale equations") },
80 ErrorSpec { code: "E-HOMOTOPY-004", class: "HomotopyError", cause: Cause::Resource, remediation: Some("adjust predictor step or increase max_tracker_steps") },
81 ErrorSpec { code: "E-JIT-001", class: "JitError", cause: Cause::Unsupported, remediation: Some("use eval_expr or simplify the expression before JIT") },
83 ErrorSpec { code: "E-JIT-002", class: "JitError", cause: Cause::Resource, remediation: Some("check LLVM 15 installation; run with RUST_LOG=debug for details") },
84 ErrorSpec { code: "E-JIT-003", class: "JitError", cause: Cause::Resource, remediation: Some("ensure LLVM_SYS_150_PREFIX is set correctly") },
85 ErrorSpec {
87 code: "E-CAD-001",
88 class: "CadError",
89 cause: Cause::Unsupported,
90 remediation: Some(
91 "use a purely polynomial constraint in one real variable without nested quantifiers; multivariate QE is incremental",
92 ),
93 },
94 ErrorSpec { code: "E-CUDA-001", class: "CudaError", cause: Cause::Resource, remediation: Some("rebuild LLVM with nvptx64 in LLVM_TARGETS_TO_BUILD") },
96 ErrorSpec { code: "E-CUDA-002", class: "CudaError", cause: Cause::Unsupported, remediation: Some("inspect PTX; verify every primitive has CUDA lowering") },
97 ErrorSpec { code: "E-CUDA-003", class: "CudaError", cause: Cause::Resource, remediation: Some("run nvidia-smi; retry with CUDA_LAUNCH_BLOCKING=1") },
98 ErrorSpec { code: "E-CUDA-004", class: "CudaError", cause: Cause::Unsupported, remediation: Some("V1.0 stub; track feature request") },
99 ErrorSpec { code: "E-CUDA-005", class: "CudaError", cause: Cause::Resource, remediation: Some("install nvidia-cuda-toolkit or set ALKAHEST_LIBDEVICE_PATH") },
100 ErrorSpec { code: "E-CUDA-006", class: "CudaError", cause: Cause::Resource, remediation: Some("check grid/block dimensions; rerun with compute-sanitizer") },
101 ErrorSpec { code: "E-IO-001", class: "IoError", cause: Cause::Resource, remediation: None },
103 ErrorSpec { code: "E-IO-002", class: "IoError", cause: Cause::UserInput, remediation: Some("file is not an alkahest pool; check the path or regenerate with ExprPool::checkpoint()") },
104 ErrorSpec { code: "E-IO-003", class: "IoError", cause: Cause::UserInput, remediation: Some("run `alkahest migrate-pool` to upgrade the file, or regenerate from source") },
105 ErrorSpec { code: "E-IO-004", class: "IoError", cause: Cause::Resource, remediation: Some("file was truncated (likely a crash during checkpoint); rerun from source and checkpoint again") },
106 ErrorSpec { code: "E-IO-005", class: "IoError", cause: Cause::UserInput, remediation: None },
107 ErrorSpec { code: "E-IO-006", class: "IoError", cause: Cause::UserInput, remediation: None },
108 ErrorSpec { code: "E-IO-007", class: "IoError", cause: Cause::UserInput, remediation: None },
109 ErrorSpec { code: "E-IO-008", class: "IoError", cause: Cause::UserInput, remediation: None },
110 ErrorSpec { code: "E-IO-009", class: "IoError", cause: Cause::UserInput, remediation: None },
111 ErrorSpec { code: "E-MOD-001", class: "ModularError", cause: Cause::UserInput, remediation: Some("use a prime modulus p ≥ 2, e.g. 101, 1009, 32749") },
113 ErrorSpec { code: "E-MOD-002", class: "ModularError", cause: Cause::UserInput, remediation: Some("ensure all images share the same variable ordering and modulus") },
114 ErrorSpec { code: "E-MOD-003", class: "ModularError", cause: Cause::UserInput, remediation: Some("provide at least one (MultiPolyFp, prime) pair") },
115 ErrorSpec { code: "E-MOD-004", class: "ModularError", cause: Cause::Unsupported, remediation: Some("provide more modular images so the prime product M exceeds 2 * max_coeff²") },
116 ErrorSpec { code: "E-LAT-001", class: "LatticeError", cause: Cause::UserInput, remediation: Some("pass a non-empty matrix of integer rows, all of equal length") },
118 ErrorSpec { code: "E-LAT-002", class: "LatticeError", cause: Cause::UserInput, remediation: Some("every row must lie in ℤ^m for fixed ambient dimension m") },
119 ErrorSpec { code: "E-LAT-003", class: "LatticeError", cause: Cause::UserInput, remediation: Some("pick δ strictly between ¼ and 1; the default δ = ¾ is standard") },
120 ErrorSpec { code: "E-LAT-004", class: "LatticeError", cause: Cause::Unsupported, remediation: Some("check for rank deficiency; try a smaller basis or report a minimal reproducer") },
121 ErrorSpec { code: "E-LOGIC-001", class: "LogicError", cause: Cause::UserInput, remediation: Some("pass a predicate or quantified Expr; use pool.gt/… or And/Or/Not") },
123 ErrorSpec { code: "E-PSLQ-001", class: "PslqError", cause: Cause::UserInput, remediation: Some("pass at least two constants that might admit a linear dependence") },
125 ErrorSpec { code: "E-PSLQ-002", class: "PslqError", cause: Cause::UserInput, remediation: Some("literals must not truncate to zero — use higher precision or decimal strings") },
126 ErrorSpec { code: "E-PSLQ-003", class: "PslqError", cause: Cause::UserInput, remediation: Some("allocate at least 64 MPFR bits; ≈664 bits ≈ 200 decimal digits") },
127 ErrorSpec { code: "E-RSOLVE-001", class: "RsolveError", cause: Cause::UserInput, remediation: Some("write the recurrence as a sum of pool.func(seq, [n ± integer]) shifts plus a polynomial in n, then call rsolve(equation, n, seq_name)") },
129 ErrorSpec { code: "E-RSOLVE-002", class: "RsolveError", cause: Cause::UserInput, remediation: Some("each addend may contain at most one sequence application; avoid products like n*f(n)") },
130 ErrorSpec { code: "E-RSOLVE-003", class: "RsolveError", cause: Cause::UserInput, remediation: Some("clear denominators; the rhs must be a polynomial in the recurrence index") },
131 ErrorSpec { code: "E-RSOLVE-004", class: "RsolveError", cause: Cause::Unsupported, remediation: Some("order > 2 non-homogeneous systems and some characteristic factorizations are not implemented yet") },
132 ErrorSpec { code: "E-RSOLVE-005", class: "RsolveError", cause: Cause::UserInput, remediation: Some("pass exactly order-many initial samples as a dict n → Expr value") },
133 ErrorSpec { code: "E-DIOPH-001", class: "DiophantineError", cause: Cause::UserInput, remediation: Some("pass one polynomial equation = 0 in two integer symbols") },
135 ErrorSpec { code: "E-DIOPH-002", class: "DiophantineError", cause: Cause::UserInput, remediation: Some("clear denominators; coefficients must be rational integers") },
136 ErrorSpec { code: "E-DIOPH-003", class: "DiophantineError", cause: Cause::Unsupported, remediation: Some("supported: linear 2-variable, x²+y²=n, x²−D·y²=N including unit Pell (no xy term); very large integers may be unsupported") },
137 ErrorSpec { code: "E-DIOPH-004", class: "DiophantineError", cause: Cause::Domain, remediation: Some("check gcd divisibility (linear) or solvability over ℤ (quadratic)") },
138 ErrorSpec { code: "E-PROD-001", class: "ProductError", cause: Cause::Unsupported, remediation: Some("reduce the term to ℚ(k) with only ℤ-linear factors in k (no extra symbols in k)") },
140 ErrorSpec { code: "E-PROD-002", class: "ProductError", cause: Cause::Internal, remediation: Some("report the polynomial as a minimal failing example") },
141 ErrorSpec { code: "E-PROD-003", class: "ProductError", cause: Cause::Unsupported, remediation: Some("ℤ-irreducible factors of degree ≥ 2 in k require a Gamma extension beyond this path") },
142 ErrorSpec { code: "E-PROD-004", class: "ProductError", cause: Cause::UserInput, remediation: Some("check that lo/hi share the ExprPool with the summation index symbol") },
143 ErrorSpec { code: "E-NT-001", class: "NumberTheoryError", cause: Cause::UserInput, remediation: Some("pass decimal strings parsable into fmpz") },
145 ErrorSpec { code: "E-NT-002", class: "NumberTheoryError", cause: Cause::Domain, remediation: Some("check positivity / parity constraints on arguments") },
146 ErrorSpec { code: "E-NT-003", class: "NumberTheoryError", cause: Cause::Domain, remediation: Some("adjust residue, base, or root degree until a modular solution exists") },
147 ErrorSpec { code: "E-NT-004", class: "NumberTheoryError", cause: Cause::Domain, remediation: Some("use prime moduli for discrete_log/nthroot_mod as documented") },
148 ErrorSpec { code: "E-NT-005", class: "NumberTheoryError", cause: Cause::Unsupported, remediation: Some("use quadratic roots or gcd(k,p−1)=1; general radicals require more machinery") },
149 ErrorSpec { code: "E-PARSE-001", class: "ParseError", cause: Cause::UserInput, remediation: Some("only ASCII arithmetic expressions are supported") },
151 ErrorSpec { code: "E-PARSE-002", class: "ParseError", cause: Cause::UserInput, remediation: Some("check parentheses and operator placement") },
152 ErrorSpec { code: "E-PARSE-003", class: "ParseError", cause: Cause::UserInput, remediation: Some("use a known function: sin, cos, tan, sinh, cosh, tanh, asin, acos, atan, atan2, exp, log, sqrt, abs, sign, floor, ceil, round, erf, erfc, gamma") },
153 ];
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159 use std::collections::HashSet;
160
161 #[test]
162 fn no_duplicate_codes() {
163 let mut seen = HashSet::new();
164 for spec in REGISTRY {
165 assert!(
166 seen.insert(spec.code),
167 "duplicate error code in REGISTRY: {}",
168 spec.code
169 );
170 }
171 }
172
173 #[test]
174 fn codes_ascending_within_prefix() {
175 let mut by_prefix: std::collections::BTreeMap<&str, Vec<u32>> =
176 std::collections::BTreeMap::new();
177 for spec in REGISTRY {
178 if let Some(pos) = spec.code.rfind('-') {
179 let prefix = &spec.code[..pos];
180 if let Ok(num) = spec.code[pos + 1..].parse::<u32>() {
181 by_prefix.entry(prefix).or_default().push(num);
182 }
183 }
184 }
185 for (prefix, nums) in &by_prefix {
186 let mut sorted = nums.clone();
187 sorted.sort_unstable();
188 assert_eq!(
189 nums, &sorted,
190 "codes under prefix {prefix} are not in ascending order"
191 );
192 }
193 }
194}