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
use crate::chebyshev::ChebyshevError;
use crate::solvers::SolverError;
use cert::AbsUncertainty;
use std::ops::Range;
#[derive(Debug)]
pub enum Kind {
Stimulus,
Response,
}
#[allow(clippy::module_name_repetitions)]
#[derive(Debug, thiserror::Error)]
pub enum PolyCalError<E> {
/// The input value was outside of the calibration range, so a prediction cannot be reliably
/// made.
///
/// In this scenario we return the value anyway because the caller needs to decide what to do.
/// In some scenarios using the value might be acceptable, particularly when the input value
/// was very close to the calibration range. Alternatively if the caller is running an
/// unconstrained optimisation the solver could leave the finite function domain. In that case,
/// as long as the value solved for lies in the function domain at the end of the optimisation
/// there is no harm in leaving it during the solve.
///
/// Note though that guarantees around monotonicity are only made within the domain of the
/// polynomial. It is possible a root outside the domain may be found, and it is the
/// responsibility of the caller to check.
#[error("input {kind:?} ({value}) is out of {kind:?} calibration working range: {range:?}")]
OutOfRangeCertain {
value: E,
evaluated: E,
range: Range<E>,
kind: Kind,
},
/// The input value was outside of the calibration range, so a prediction cannot be reliably
/// made.
///
/// In this scenario we return the value anyway because the caller needs to decide what to do.
/// In some scenarios using the value might be acceptable, particularly when the input value
/// was very close to the calibration range. Alternatively if the caller is running an
/// unconstrained optimisation the solver could leave the finite function domain. In that case,
/// as long as the value solved for lies in the function domain at the end of the optimisation
/// there is no harm in leaving it during the solve.
///
/// Note though that guarantees around monotonicity are only made within the domain of the
/// polynomial. It is possible a root outside the domain may be found, and it is the
/// responsibility of the caller to check.
#[error("input {kind:?} ({value}) is out of {kind:?} calibration working range: {range:?}")]
OutOfRangeUncertain {
value: E,
evaluated: AbsUncertainty<E>,
range: Range<E>,
kind: Kind,
},
/// Failure in the underlying inverse solver.
#[error("failed to solve inverse problem")]
InverseSolver(#[from] argmin::core::Error),
/// Failure in the underlying least-squares routine
#[error("failed to solve least-squares problem")]
LeastSquares(#[from] SolverError),
/// There was no minimum found using the requested scoring strategy.
#[error("no minimum found: {scores:?}. perhaps try a different scoring criteria?")]
NoMinimum { scores: Vec<E> },
/// Input data contained invalid values, leaving the calculation unable to proceed
#[error("provided data must be free of NaN, or infinities")]
InvalidData(String),
/// Error in low-level Chebyshev calculation
#[error("error in chebyshev calculation")]
Chebyshev(ChebyshevError),
#[error("a successful fit was not possible for the given data")]
FittingFailure {
dependent: Vec<E>,
independent: Vec<E>,
},
}