1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use std::error::Error;
use std::fmt::{Display, Formatter};
/// Describes why the nonlinear solve stopped.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TerminationReason {
/// The residual or method-specific convergence check succeeded.
Converged,
/// The maximum number of outer iterations was reached.
MaxIterations,
/// The trial step became too small to make progress.
StepTooSmall,
/// The method stopped because progress stalled.
Stagnation,
/// Too many trial steps were rejected.
RejectedStepLimit,
}
/// Errors returned by the nonlinear solver pipeline.
#[derive(Debug, Clone, PartialEq)]
pub enum SolveError {
/// A vector or matrix has an unexpected dimension.
DimensionMismatch {
/// Expected dimension.
expected: usize,
/// Actual dimension.
actual: usize,
/// Short description of the failing context.
context: &'static str,
},
/// Solver configuration is invalid.
InvalidConfig(String),
/// Initial point violates the provided bounds.
InfeasibleInitialGuess {
/// Index of the offending variable.
index: usize,
/// Current variable value.
value: f64,
/// Lower bound.
lower: f64,
/// Upper bound.
upper: f64,
},
/// Residual evaluation failed.
ResidualEvaluation(String),
/// Jacobian evaluation failed.
JacobianEvaluation(String),
/// Compiled AOT artifact was selected, but no linked in-process runtime was available.
CompiledAotRuntimeUnavailable(String),
/// A compiled AOT artifact was required, but no registered artifact exists.
CompiledAotArtifactMissing(String),
/// A generated AOT crate is known, but the compiled artifact is not built yet.
CompiledAotArtifactNotBuilt(String),
/// Automatic AOT build was requested without an output directory.
AotBuildOutputDirMissing,
/// Automatic AOT build failed.
AotBuildFailed(String),
/// Linear system solve failed.
LinearSolveFailure(String),
/// Jacobian is singular or too ill-conditioned.
SingularJacobian,
/// Numerical breakdown such as NaN or Inf.
NumericalBreakdown(String),
}
impl Display for SolveError {
/// Formats a human-readable error message.
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
SolveError::DimensionMismatch {
expected,
actual,
context,
} => {
write!(
f,
"dimension mismatch in {context}: expected {expected}, got {actual}"
)
}
SolveError::InvalidConfig(msg) => write!(f, "invalid solver configuration: {msg}"),
SolveError::InfeasibleInitialGuess {
index,
value,
lower,
upper,
} => write!(
f,
"initial guess at index {index} = {value} violates bounds [{lower}, {upper}]"
),
SolveError::ResidualEvaluation(msg) => write!(f, "residual evaluation failed: {msg}"),
SolveError::JacobianEvaluation(msg) => write!(f, "jacobian evaluation failed: {msg}"),
SolveError::CompiledAotRuntimeUnavailable(msg) => {
write!(f, "compiled AOT runtime unavailable: {msg}")
}
SolveError::CompiledAotArtifactMissing(msg) => {
write!(f, "compiled AOT artifact missing: {msg}")
}
SolveError::CompiledAotArtifactNotBuilt(msg) => {
write!(f, "compiled AOT artifact not built: {msg}")
}
SolveError::AotBuildOutputDirMissing => {
write!(
f,
"automatic AOT build requested without an output directory"
)
}
SolveError::AotBuildFailed(msg) => write!(f, "automatic AOT build failed: {msg}"),
SolveError::LinearSolveFailure(msg) => write!(f, "linear solve failed: {msg}"),
SolveError::SingularJacobian => write!(f, "jacobian is singular or ill-conditioned"),
SolveError::NumericalBreakdown(msg) => write!(f, "numerical breakdown: {msg}"),
}
}
}
impl Error for SolveError {}