chore: remove deprecated flow_boundary and update docs to match new architecture
This commit is contained in:
@@ -177,6 +177,62 @@ impl JacobianMatrix {
|
||||
}
|
||||
}
|
||||
|
||||
/// Estimates the condition number of the Jacobian matrix.
|
||||
///
|
||||
/// The condition number κ = σ_max / σ_min indicates how ill-conditioned
|
||||
/// the matrix is. Values > 1e10 indicate an ill-conditioned system that
|
||||
/// may cause numerical instability in the solver.
|
||||
///
|
||||
/// Uses SVD decomposition to compute singular values. This is an O(n³)
|
||||
/// operation and should only be used for diagnostics.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Some(κ)` - The condition number (ratio of largest to smallest singular value)
|
||||
/// * `None` - If the matrix is rank-deficient (σ_min = 0)
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use entropyk_solver::jacobian::JacobianMatrix;
|
||||
///
|
||||
/// // Well-conditioned matrix
|
||||
/// let entries = vec![(0, 0, 2.0), (1, 1, 1.0)];
|
||||
/// let j = JacobianMatrix::from_builder(&entries, 2, 2);
|
||||
/// let cond = j.estimate_condition_number().unwrap();
|
||||
/// assert!(cond < 10.0, "Expected low condition number, got {}", cond);
|
||||
///
|
||||
/// // Ill-conditioned matrix (nearly singular)
|
||||
/// let bad_entries = vec![(0, 0, 1.0), (0, 1, 1.0), (1, 0, 1.0), (1, 1, 1.0000001)];
|
||||
/// let bad_j = JacobianMatrix::from_builder(&bad_entries, 2, 2);
|
||||
/// let bad_cond = bad_j.estimate_condition_number().unwrap();
|
||||
/// assert!(bad_cond > 1e7, "Expected high condition number, got {}", bad_cond);
|
||||
/// ```
|
||||
pub fn estimate_condition_number(&self) -> Option<f64> {
|
||||
// Handle empty matrices
|
||||
if self.0.nrows() == 0 || self.0.ncols() == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Use SVD to get singular values
|
||||
let svd = self.0.clone().svd(true, true);
|
||||
|
||||
// Get singular values
|
||||
let singular_values = svd.singular_values;
|
||||
|
||||
if singular_values.len() == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let sigma_max = singular_values.max();
|
||||
let sigma_min = singular_values.iter().filter(|&&s| s > 0.0).min_by(|a, b| a.partial_cmp(b).unwrap()).copied();
|
||||
|
||||
match sigma_min {
|
||||
Some(min) => Some(sigma_max / min),
|
||||
None => None, // Matrix is rank-deficient
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes a numerical Jacobian via finite differences.
|
||||
///
|
||||
/// For each state variable x_j, perturbs by epsilon and computes:
|
||||
|
||||
Reference in New Issue
Block a user