fix(math): preflight finite dense operands at dispatch boundary

This commit is contained in:
KOKO\Mimi
2026-10-14 16:02:17 +09:00
parent 770fa2a0d1
commit 9c4e6854ae
8 changed files with 65 additions and 5 deletions
+6 -1
View File
@@ -5,6 +5,7 @@
#include <cmath>
#include <limits>
#include <map>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
@@ -226,7 +227,7 @@ Result<EigenReduction> BuildEigenReduction(
const SparseMatrix& stiffness, const std::vector<Matrix>& mass,
const std::vector<ShellNodeInitialFrame>& frames,
const std::vector<std::uint8_t>& mask, const std::vector<double>& drilling,
const double length) {
const double length) try {
const std::size_t count = mass.size();
const Status valid = stiffness.Validate();
if (!valid.IsOk()) return Result<EigenReduction>::Failure(valid);
@@ -401,6 +402,10 @@ Result<EigenReduction> BuildEigenReduction(
return Result<EigenReduction>::Success(
{std::move(reduced.Value()), std::move(lifts), free_count, null_count,
length, eta_mz, eta_kz, pz_norm});
} catch (const std::invalid_argument&) {
return Result<EigenReduction>::Failure(
Failure("invalid-eigen-mass-space", 0U,
"Eigen product operands must be finite and shape compatible."));
}
Vector RestoreScaledMode(const EigenReduction& reduction, const Matrix& vectors,
@@ -275,6 +275,10 @@ Result<EigenAnalysisState> ExecuteCandidate(const Domain& domain) {
std::size_t pivot = 0U;
for (std::size_t dof = 0; dof < y.Size(); ++dof) {
physical[dof] = D(dof, length) * y[dof];
if (!std::isfinite(physical[dof]))
return Result<EigenAnalysisState>::Failure(
MetricFailure("initial_modal_mass", physical[dof],
state.backend.column_ids[column]));
if (std::abs(y[dof]) > std::abs(y[pivot])) pivot = dof;
}
Vector mass_times = eigen_internal::MultiplyNodalMass(nodal_mass, physical);
@@ -413,6 +417,10 @@ Result<EigenAnalysisState> LinearFrequencyProcedureExecutor::Execute(
std::move(diagnostics)));
}
return result;
} catch (const std::invalid_argument&) {
return Result<EigenAnalysisState>::Failure(
Failure("invalid-eigenvalue-result", "modal-workspace",
"Modal product inputs must be finite and shape compatible."));
} catch (const std::bad_alloc&) {
return Result<EigenAnalysisState>::Failure(
Failure("eigen-allocation-failed", "modal-workspace",
+1 -1
View File
@@ -31,7 +31,7 @@ class ScopedSingleEquationThreads {
Result<MKL_INT> ToMklSize(std::size_t size);
/// @brief Computes left-transpose times right through ordinary dense MKL.
/// @throws std::invalid_argument if the row counts differ.
/// @throws std::invalid_argument for mismatched rows or nonfinite operands.
Matrix MultiplyTransposeLeft(const Matrix& left, const Matrix& right);
/// @brief Multiplies a compact diagonal matrix by a vector through MKL.
+13
View File
@@ -1,5 +1,6 @@
#include "fesa/math/matrix.h"
#include <cmath>
#include <mkl.h>
#include <limits>
@@ -107,6 +108,12 @@ Vector Matrix::Multiply(const Vector& rhs) const {
throw std::invalid_argument{
"Matrix-vector multiplication has incompatible dimensions."};
}
for (const double value : values_)
if (!std::isfinite(value))
throw std::invalid_argument{"Matrix product inputs must be finite."};
for (std::size_t i = 0; i < rhs.Size(); ++i)
if (!std::isfinite(rhs.Data()[i]))
throw std::invalid_argument{"Matrix product inputs must be finite."};
Vector result{rows_};
if (rows_ == 0 || columns_ == 0) {
@@ -126,6 +133,12 @@ Matrix Matrix::Multiply(const Matrix& rhs) const {
throw std::invalid_argument{
"Matrix multiplication has incompatible dimensions."};
}
for (const double value : values_)
if (!std::isfinite(value))
throw std::invalid_argument{"Matrix product inputs must be finite."};
for (const double value : rhs.values_)
if (!std::isfinite(value))
throw std::invalid_argument{"Matrix product inputs must be finite."};
Matrix result{rows_, rhs.columns_};
if (rows_ == 0 || columns_ == 0 || rhs.columns_ == 0) {
@@ -1194,8 +1194,13 @@ Result<FeastEigenResult> MklFeastEigenSolver::SolveImpl(
for (std::size_t row = 0; row < n; ++row)
mode[row] = ordered_vectors(row, right);
const auto action = mass != nullptr ? mass->Multiply(mode) : std::move(mode);
for (std::size_t row = 0; row < n; ++row)
for (std::size_t row = 0; row < n; ++row) {
if (!std::isfinite(action[row]))
return Result<FeastEigenResult>::Failure(
TraceFailure("eigenpair-validation-failed", "gram",
"The independent mass action is nonfinite."));
mass_modes(row, right) = action[row];
}
}
const auto gram = dense_blas_internal::MultiplyTransposeLeft(ordered_vectors,
mass_modes);
@@ -1245,6 +1250,10 @@ Result<FeastEigenResult> MklFeastEigenSolver::SolveImpl(
solve_upper,
upper_search_termination};
return Result<FeastEigenResult>::Success(std::move(result));
} catch (const std::invalid_argument&) {
return Result<FeastEigenResult>::Failure(
Failure("eigenpair-validation-failed", "independent-action",
"Modal product inputs must be finite and shape compatible."));
} catch (const std::length_error&) {
return Result<FeastEigenResult>::Failure(
Failure("feast-integer-overflow", "independent-action",