• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geo-ant / varpro / 19345421338

13 Nov 2025 08:49PM UTC coverage: 86.555% (+10.2%) from 76.356%
19345421338

Pull #53

github

web-flow
Merge ec5d02857 into f4e94d710
Pull Request #53: Feature/nalgebra lapack qr calculations refactor

182 of 231 new or added lines in 10 files covered. (78.79%)

8 existing lines in 2 files now uncovered.

1030 of 1190 relevant lines covered (86.55%)

3692.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

64.71
/src/problem.rs
1
use crate::prelude::*;
2
use crate::util::Weights;
3
use nalgebra::Dyn;
4
use nalgebra::{ComplexField, DMatrix, MatrixView, Scalar, VectorView};
5

6
mod builder;
7

8
pub use builder::SeparableProblemBuilder;
9
pub use builder::SeparableProblemBuilderError;
10

11
/// trait describing the type of right hand side for the problem, meaning either
12
/// a single right hand side or multiple right hand sides. The latter implies
13
/// global fitting.
14
pub trait RhsType: std::fmt::Debug {}
15

16
/// This type indicates that the associated problem has a single (vector) right hand side.
17
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
18
pub struct SingleRhs;
19

20
/// This type indicates that the associated problem has multiple right hand sides
21
/// and thus performs global fitting for the nonlinear parameters.
22
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
23
pub struct MultiRhs;
24

25
impl RhsType for MultiRhs {}
26
impl RhsType for SingleRhs {}
27

28
/// This is the problem of fitting the separable model to data in a form that the
29
/// [levenberg_marquardt](https://crates.io/crates/levenberg-marquardt) crate can use it to
30
/// perform the least squares fit.
31
///
32
/// # Construction
33
///
34
/// Use the [`SeparableProblemBuilder`] to create an instance of a
35
/// levmar problem.
36
///
37
/// # Usage
38
///
39
/// After obtaining an instance of [`SeparableProblem`] we can pass it to the [`LevMarSolver`](crate::solvers::levmar::LevMarSolver)
40
/// which uses the Levenberg-Marquardt algorithm from the levenberg_marquardt crate for minimization.
41
/// Refer to the documentation of the [levenberg_marquardt](https://crates.io/crates/levenberg-marquardt)
42
/// crate for an overview of the algorithm. A usage example is provided in this crate's documentation as well.
43
///
44
/// # Right Hand Sides: Single vs Multiple
45
///
46
/// The problem is generic over the `Rhs` type parameter which indicates whether the
47
/// problem fits a single ([`SingleRhs`]) or multiple ([`MultiRhs`]) right
48
/// hand sides. This is decided during the building process. The underlying
49
/// math does not change, but the interface changes to use vectors for coefficients
50
/// and data in case of a single right hand side. For multiple right hand sides,
51
/// the coefficients and the data are matrices corresponding to columns of
52
/// coefficient vectors and data vectors respectively.
53
#[derive(Clone)]
54
#[allow(non_snake_case)]
55
pub struct SeparableProblem<Model, Rhs: RhsType>
56
where
57
    Model: SeparableNonlinearModel,
58
    Model::ScalarType: Scalar + ComplexField + Copy,
59
{
60
    /// The *weighted* data matrix to which to fit the model `$\boldsymbol{Y}_w$`.
61
    /// It is a matrix so it can accommodate multiple right hand sides. If
62
    /// the problem has only a single right hand side (SingleRhs), this is just
63
    /// a matrix with one column. The underlying math does not change in either case.
64
    /// **Attention:** The data matrix is weighted with the weights if some weights
65
    /// were provided (otherwise it is unweighted)
66
    pub(crate) Y_w: DMatrix<Model::ScalarType>,
67
    /// a reference to the separable model we are trying to fit to the data
68
    pub(crate) model: Model,
69
    /// the weights of the data. If none are given, the data is not weighted
70
    /// If weights were provided, the builder has checked that the weights have the
71
    /// correct dimension for the data
72
    pub(crate) weights: Weights<Model::ScalarType, Dyn>,
73
    phantom: std::marker::PhantomData<Rhs>,
74
}
75

76
impl<Model, Rhs: RhsType> std::fmt::Debug for SeparableProblem<Model, Rhs>
77
where
78
    Model: SeparableNonlinearModel,
79
    Model::ScalarType: Scalar + ComplexField + Copy,
80
{
81
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3✔
82
        f.debug_struct("SeparableProblem")
15✔
83
            .field("y_w", &self.Y_w)
12✔
84
            .field("model", &"/* omitted */")
9✔
85
            .field("weights", &self.weights)
6✔
86
            .finish()
87
    }
88
}
89

90
impl<Model> SeparableProblem<Model, MultiRhs>
91
where
92
    Model: SeparableNonlinearModel,
93
    Model::ScalarType: Scalar + ComplexField + Copy,
94
{
95
    /// The weighted data matrix `$\boldsymbol{Y}_w$` to which to fit the model. Note
96
    /// that the weights are already applied to the data matrix and this
97
    /// is not the original data vector.
98
    ///
99
    /// This method is for fitting multiple right hand sides, hence the data
100
    /// matrix is a matrix that contains the right hand sides as columns.
NEW
101
    pub fn weighted_data(&self) -> MatrixView<'_, Model::ScalarType, Dyn, Dyn> {
×
102
        self.Y_w.as_view()
×
103
    }
104
}
105

106
impl<Model> SeparableProblem<Model, SingleRhs>
107
where
108
    Model: SeparableNonlinearModel,
109
    Model::ScalarType: Scalar + ComplexField + Copy,
110
{
111
    /// The weighted data vector `$\vec{y}_w$` to which to fit the model. Note
112
    /// that the weights are already applied to the data vector and this
113
    /// is not the original data vector.
114
    ///
115
    /// This method is for fitting a single right hand side, hence the data
116
    /// is a single column vector.
117
    pub fn weighted_data(&self) -> VectorView<'_, Model::ScalarType, Dyn> {
18✔
118
        debug_assert_eq!(
18✔
119
            self.Y_w.ncols(),
36✔
120
            1,
×
121
            "data matrix must have exactly one column for single right hand side. This indicates a programming error in the library."
×
122
        );
123
        self.Y_w.as_view()
36✔
124
    }
125
}
126

127
impl<Model, Rhs: RhsType> SeparableProblem<Model, Rhs>
128
where
129
    Model: SeparableNonlinearModel,
130
    Model::ScalarType: Scalar + ComplexField + Copy,
131
{
132
    /// access the contained model immutably
133
    pub fn model(&self) -> &Model {
102✔
134
        &self.model
102✔
135
    }
136

137
    /// get the weights of the data for the fitting problem
UNCOV
138
    pub fn weights(&self) -> &Weights<Model::ScalarType, Dyn> {
×
UNCOV
139
        &self.weights
×
140
    }
141
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc