Report factor value bytes and preserve overflow-safe reduction limits

This commit is contained in:
Preetinder Kalsi authored and Irakli Kourtis committed 2026-10-15 14:00:56 -04:00
1 parent c7d0a82079
commit a530a0d914
7 files changed
+80 -12

No files matched your search

+18 -3
View File
@@ -266,9 +266,7 @@ pub(crate) fn factor_symmetric(a: &Csr, limits: &Limits, kind: Kind) -> std::res
/// a singular pivot.
pub(crate) fn factor_error(e: FactorError, mesh: &Mesh, reduction: &Reduction) -> Error {
match e {
FactorError::TooLarge { entries, limit } => {
Error::Limit(format!("the factorization needs {entries} entries; the limit is {limit} (refine less or raise the limit)"))
}
FactorError::TooLarge { entries, limit } => Error::factor_limit(entries, limit),
FactorError::OutOfMemory { entries } => Error::Limit(format!("not enough memory for the factorization ({entries} entries)")),
FactorError::Internal(what) => Error::Internal(what),
FactorError::Cancelled => Error::Model(fieldcraft_model::Error::Cancelled),
@@ -733,3 +731,20 @@ impl StepResult {
.map(Location::Point)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn raised_factor_budget_keeps_the_lanczos_vector_limit() {
let neq = Limits::MAX_DOFS;
for (entries, expected) in [(400_000_000, 33), (2_000_000_000, 166)] {
let limits = Limits { max_factor_entries: entries, ..Limits::default() };
let vectors = lanczos_basis(&limits, neq);
assert_eq!(vectors, expected);
assert!(2 * neq * vectors <= entries);
assert_eq!(lanczos_basis(&Limits { max_lanczos_vectors: 7, ..limits }, neq), 7);
}
}
}
+16 -1
View File
@@ -367,7 +367,7 @@ impl Budget {
}
fn exceeded(&self, entries: usize) -> bool {
self.bytes(entries) > self.max_bytes
entries > self.max_bytes / (8 * (1 + self.matrices))
}
}
@@ -770,3 +770,18 @@ impl Reduction {
out
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reduced_matrix_budget_refuses_byte_counts_that_overflow() {
for matrices in [1, 2] {
let budget = Budget { max_bytes: usize::MAX, pattern_entries: 0, matrices };
let entries = usize::MAX / (8 * (1 + matrices));
assert!(!budget.exceeded(entries));
assert!(budget.exceeded(entries + 1));
}
}
}
+1 -3
View File
@@ -303,9 +303,7 @@ fn prescribed(model: &Model, resolved: &Resolved, mesh: &HeatMesh, step: &Step)
fn factor(a: &Csr, limits: &Limits, mesh: &HeatMesh, eqs: &Reduction) -> Result<Factor> {
Factor::new(&UpperColumns::from_symmetric(a), limits.max_factor_entries).map_err(|e| match e {
FactorError::TooLarge { entries, limit } => {
Error::Limit(format!("the factorization needs {entries} entries; the limit is {limit} (refine less or raise the limit)"))
}
FactorError::TooLarge { entries, limit } => Error::factor_limit(entries, limit),
FactorError::OutOfMemory { entries } => Error::Limit(format!("not enough memory for the factorization ({entries} entries)")),
FactorError::Internal(what) => Error::Internal(what),
FactorError::Cancelled => Error::Model(fieldcraft_model::Error::Cancelled),
+24
View File
@@ -76,6 +76,14 @@ pub enum Error {
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
/// Factor-value bytes alone; indices and numeric workspace need additional memory.
pub(crate) fn factor_limit(entries: usize, limit: usize) -> Error {
let bytes = entries as u128 * std::mem::size_of::<f64>() as u128;
Error::Limit(format!(
"the factorization needs {entries} entries ({bytes} bytes of factor values alone; indices and workspace are additional); the limit is {limit} entries (refine less or raise max_factor_entries)"
))
}
/// A kernel error, naming the element.
pub fn element(label: u32, source: fieldcraft_fem::Error) -> Error {
Error::Element { label, source }
@@ -112,3 +120,19 @@ impl Default for Limits {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn factor_limit_estimates_bytes_without_allocating_the_factor() {
for (entries, bytes) in [(467_000_000, "3736000000"), (2_000_000_000, "16000000000")] {
let e = Error::factor_limit(entries, 400_000_000).to_string();
assert!(e.contains(&format!("{entries} entries ({bytes} bytes of factor values alone")), "{e}");
assert!(e.contains("indices and workspace are additional"), "{e}");
assert!(e.contains("limit is 400000000 entries"), "{e}");
assert!(e.contains("raise max_factor_entries"), "{e}");
}
}
}