perf(math): route ordinary products through MKL and preserve arithmetic

This commit is contained in:
KOKO\Mimi
2026-10-14 15:09:53 +09:00
parent b4fc1bb54b
commit 59c8e93b07
18 changed files with 793 additions and 169 deletions
+52 -14
View File
@@ -3,6 +3,7 @@
#include <algorithm>
#include <cmath>
#include <limits>
#include <stdexcept>
#include <string>
#include <utility>
@@ -116,6 +117,14 @@ Result<Equations> Build(const ThermalSystem& s, const ThermalPartition& p,
constrained[p.constrained[i]] = i;
SparsePattern pattern{{0}, {}};
std::vector<CooContribution> coo;
SparsePattern rhs_pattern{{0U}, {}};
std::vector<CooContribution> capacity_rhs, conductivity_rhs;
Vector capacity_input = old;
Vector prescribed_full{m};
std::vector<bool> capacity_column_used(m, false);
for (std::size_t i = 0; i < p.constrained.size(); ++i) {
prescribed_full[p.constrained[i]] = p.prescribed[i];
}
Vector b{n};
std::vector<I> exact_a, exact_b(n);
for (std::size_t f = 0; f < n; ++f) {
@@ -126,22 +135,43 @@ Result<Equations> Build(const ThermalSystem& s, const ThermalPartition& p,
const auto col = s.c.ColumnIndices()[j];
const double c = s.c.Values()[j], k = s.k.Values()[j];
const I cd = Div(I{c}, I{delta});
rhs_pattern.column_indices.push_back(col);
capacity_column_used[col] = true;
capacity_rhs.push_back({f, col, c / delta, 0U, j});
conductivity_rhs.push_back({f, col, k, 0U, j});
if (free[col] != n) {
coo.push_back({f, free[col], c / delta + k, 0, coo.size()});
pattern.column_indices.push_back(free[col]);
exact_a.push_back(Add(cd, I{k}));
b[f] += (c / delta) * old[col];
exact_b[f] = Add(exact_b[f], Mul(cd, I{old[col]}));
} else {
const double g = p.prescribed[constrained[col]];
// Preserve raw old constrained capacity; never project frame zero.
b[f] += (c / delta) * (old[col] - g) - k * g;
exact_b[f] = Add(exact_b[f],
Sub(Mul(cd, Sub(I{old[col]}, I{g})), Mul(I{k}, I{g})));
}
}
pattern.row_offsets.push_back(coo.size());
rhs_pattern.row_offsets.push_back(capacity_rhs.size());
}
// Do not create overflow in an absent constrained column: the original
// free-row RHS never evaluated that subtraction. Referenced structural
// zeros still evaluate it and reject nonfinite intermediate values.
for (std::size_t i = 0; i < p.constrained.size(); ++i) {
const auto column = p.constrained[i];
if (capacity_column_used[column]) capacity_input[column] -= p.prescribed[i];
}
if (!Finite(capacity_input))
return Result<Equations>::Failure(Failure("Nonfinite backward Euler RHS."));
auto c_rhs = SparseMatrix::FromCoo(n, m, std::move(capacity_rhs), rhs_pattern);
auto k_rhs = SparseMatrix::FromCoo(n, m, std::move(conductivity_rhs),
rhs_pattern);
if (!c_rhs.HasValue() || !k_rhs.HasValue())
return Result<Equations>::Failure(Failure("Nonfinite backward Euler RHS."));
const auto capacity_action = c_rhs.Value().Multiply(capacity_input);
const auto conductivity_action = k_rhs.Value().Multiply(prescribed_full);
for (std::size_t f = 0; f < n; ++f)
b[f] += capacity_action[f] - conductivity_action[f];
auto a = SparseMatrix::FromCoo(n, n, std::move(coo), pattern);
if (!a.HasValue()) return Result<Equations>::Failure(a.GetStatus());
if (!Finite(b))
@@ -178,13 +208,15 @@ Status Check(const ThermalSystem& s, const ThermalPartition& p,
I a_norm, t_norm, b_norm = Norm(eq.b);
Vector red{n}, red_error{n};
std::vector<I> construction(n);
Vector free_temperature{n};
for (std::size_t f = 0; f < n; ++f)
free_temperature[f] = candidate.temperature[p.free[f]];
const auto reduced_action = eq.a.Multiply(free_temperature);
for (std::size_t f = 0; f < n; ++f) {
I row_norm, scale, ea, identity;
double dot = 0;
for (auto j = eq.a.RowOffsets()[f]; j < eq.a.RowOffsets()[f + 1]; ++j) {
const double a = eq.a.Values()[j],
t = candidate.temperature[p.free[eq.a.ColumnIndices()[j]]];
dot += a * t;
row_norm = Add(row_norm, Magnitude(a));
scale = Add(scale, Mul(Magnitude(a), Magnitude(t)));
const I error{Error(eq.exact_a[j], a)};
@@ -193,7 +225,7 @@ Status Check(const ThermalSystem& s, const ThermalPartition& p,
}
a_norm = Max(a_norm, row_norm);
t_norm = Max(t_norm, Magnitude(candidate.temperature[p.free[f]]));
red[f] = dot - eq.b[f];
red[f] = reduced_action[f] - eq.b[f];
scale = Add(scale, Magnitude(eq.b[f]));
const double nu =
static_cast<double>(eq.a.RowOffsets()[f + 1] - eq.a.RowOffsets()[f]);
@@ -216,18 +248,19 @@ Status Check(const ThermalSystem& s, const ThermalPartition& p,
for (std::size_t i = 0; i < m; ++i)
change[i] = candidate.temperature[i] - old[i];
if (!Finite(change)) return Failure("Nonfinite temperature change.");
const auto capacity_change = s.c.Multiply(change);
const auto conductivity_new = s.k.Multiply(candidate.temperature);
I c_change, k_new, q_abs, c_temperatures, underflow_sum;
std::vector<I> k_columns(m);
double energy = 0;
for (std::size_t i = 0; i < m; ++i) {
double cd = 0, kt = 0, ksum = 0;
const double cd = capacity_change[i], kt = conductivity_new[i];
double ksum = 0;
I cs, ks, ts, cabs, nullscale, nullerror, coefficient;
for (auto j = s.c.RowOffsets()[i]; j < s.c.RowOffsets()[i + 1]; ++j) {
const auto col = s.c.ColumnIndices()[j];
const double c = s.c.Values()[j], k = s.k.Values()[j],
t = candidate.temperature[col];
cd += c * change[col];
kt += k * t;
ksum += k;
cs = Add(cs, Mul(Magnitude(c), Magnitude(change[col])));
ks = Add(ks, Mul(Magnitude(k), Magnitude(t)));
@@ -334,10 +367,13 @@ Status Check(const ThermalSystem& s, const ThermalPartition& p,
if (p.constrained.empty() && Zero(q_abs)) {
ev.dissipation_checked = true;
double cn = 0, co = 0, cd = 0, kn = 0;
const auto capacity_new = s.c.Multiply(candidate.temperature);
const auto capacity_old = s.c.Multiply(old);
I sc, subscale, t_one, d_square, o_square, skew_square, quadratic_underflow;
for (std::size_t i = 0; i < m; ++i) {
const double t = candidate.temperature[i];
double row_cn = 0, row_co = 0, row_cd = 0, row_kn = 0;
const double row_cn = capacity_new[i], row_co = capacity_old[i],
row_cd = capacity_change[i], row_kn = conductivity_new[i];
I scale_cn, scale_co, scale_cd, scale_kn;
t_one = Add(t_one, Magnitude(t));
d_square = Add(d_square, Mul(Magnitude(change[i]), Magnitude(change[i])));
@@ -345,10 +381,6 @@ Status Check(const ThermalSystem& s, const ThermalPartition& p,
for (auto j = s.c.RowOffsets()[i]; j < s.c.RowOffsets()[i + 1]; ++j) {
const auto col = s.c.ColumnIndices()[j];
const double c = s.c.Values()[j], k = s.k.Values()[j];
row_cn += c * candidate.temperature[col];
row_co += c * old[col];
row_cd += c * change[col];
row_kn += k * candidate.temperature[col];
scale_cn = Add(
scale_cn, Mul(Magnitude(c), Magnitude(candidate.temperature[col])));
scale_co = Add(scale_co, Mul(Magnitude(c), Magnitude(old[col])));
@@ -421,7 +453,7 @@ Status Check(const ThermalSystem& s, const ThermalPartition& p,
Result<ThermalStepCandidate> SolveThermalIncrement(
const ThermalSystem& s, const ThermalPartition& p, const Vector& old,
double delta, LinearSolver& solver, ThermalFactorization& cache) {
double delta, LinearSolver& solver, ThermalFactorization& cache) try {
auto status = Validate(s, p, old, delta);
if (!status.IsOk()) return Result<ThermalStepCandidate>::Failure(status);
auto equations = Build(s, p, old, delta);
@@ -461,6 +493,12 @@ Result<ThermalStepCandidate> SolveThermalIncrement(
status = Check(s, p, old, delta, equations.Value(), candidate);
if (!status.IsOk()) return Result<ThermalStepCandidate>::Failure(status);
return Result<ThermalStepCandidate>::Success(std::move(candidate));
} catch (const std::length_error&) {
return Result<ThermalStepCandidate>::Failure(
Failure("Thermal sparse action exceeds the backend integer range."));
} catch (const std::runtime_error&) {
return Result<ThermalStepCandidate>::Failure(
Failure("Thermal sparse action failed."));
}
Status RunThermalHistory(const ThermalAssembly& assembly,