Integrate Refactor solver sources and dual MSVC CMake builds
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <future>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
@@ -14,7 +13,6 @@
|
||||
#include "fesa/math/sparse_matrix.h"
|
||||
#include "fesa/math/vector.h"
|
||||
#include "fesa/solvers/linear/tangent_solver.h"
|
||||
#include "math/dense_blas_internal.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -131,104 +129,4 @@ TEST(TangentSolver, RejectsSolveBeforeSuccessfulFactorization) {
|
||||
EXPECT_DOUBLE_EQ(correction[1U], -9.0);
|
||||
}
|
||||
|
||||
TEST(TangentSolver, ReusesRhsButFreshValuesAndFailureCannotReuseStaleState) {
|
||||
fesa::MklPardisoTangentSolver solver;
|
||||
ASSERT_TRUE(solver.FactorizeFresh(MakeDenseCsr(2U, {2.0, 1.0, 0.0, 3.0}))
|
||||
.IsOk());
|
||||
fesa::Vector correction{2U};
|
||||
for (double scale : {1.0, -2.0, 0.5}) {
|
||||
ASSERT_TRUE(solver.SolveCorrection(MakeVector({4.0 * scale, 6.0 * scale}),
|
||||
correction).IsOk());
|
||||
EXPECT_NEAR(correction[0U], scale, 1.0e-14);
|
||||
EXPECT_NEAR(correction[1U], 2.0 * scale, 1.0e-14);
|
||||
}
|
||||
const auto bad_rhs = MakeVector({std::numeric_limits<double>::quiet_NaN(), 0});
|
||||
correction = MakeVector({17, -4});
|
||||
EXPECT_FALSE(solver.SolveCorrection(bad_rhs, correction).IsOk());
|
||||
EXPECT_DOUBLE_EQ(correction[0U], 17);
|
||||
EXPECT_DOUBLE_EQ(correction[1U], -4);
|
||||
ASSERT_TRUE(solver.SolveCorrection(MakeVector({4, 6}), correction).IsOk());
|
||||
ASSERT_TRUE(solver.FactorizeFresh(MakeDenseCsr(2U, {4, 0, 1, 2})).IsOk());
|
||||
ASSERT_TRUE(solver.SolveCorrection(MakeVector({4, 5}), correction).IsOk());
|
||||
EXPECT_NEAR(correction[0U], 1, 1.0e-14);
|
||||
EXPECT_NEAR(correction[1U], 2, 1.0e-14);
|
||||
auto diagonal = fesa::SparseMatrix::FromCoo(
|
||||
2U, 2U, {{0U, 0U, 5, 0U, 0U}, {1U, 1U, 7, 1U, 0U}},
|
||||
{{0U, 1U, 2U}, {0U, 1U}});
|
||||
ASSERT_TRUE(diagonal.HasValue());
|
||||
ASSERT_TRUE(solver.FactorizeFresh(diagonal.Value()).IsOk());
|
||||
ASSERT_TRUE(solver.SolveCorrection(MakeVector({10, -7}), correction).IsOk());
|
||||
EXPECT_NEAR(correction[0U], 2, 1.0e-14);
|
||||
EXPECT_NEAR(correction[1U], -1, 1.0e-14);
|
||||
EXPECT_FALSE(solver.FactorizeFresh(MakeDenseCsr(2U, {0, 0, 0, 0})).IsOk());
|
||||
correction = MakeVector({19, -8});
|
||||
const auto stale = solver.SolveCorrection(MakeVector({10, -7}), correction);
|
||||
ASSERT_FALSE(stale.IsOk());
|
||||
EXPECT_EQ(stale.Diagnostics().front().code, "solver-not-factorized");
|
||||
EXPECT_DOUBLE_EQ(correction[0U], 19);
|
||||
EXPECT_DOUBLE_EQ(correction[1U], -8);
|
||||
ASSERT_TRUE(solver.FactorizeFresh(diagonal.Value()).IsOk());
|
||||
EXPECT_TRUE(solver.SolveCorrection(MakeVector({10, -7}), correction).IsOk());
|
||||
}
|
||||
|
||||
TEST(TangentSolver, SingleEquationScopeRestoresTlsAcrossFreshFailureAndReuse) {
|
||||
const auto worker = [] {
|
||||
const int previous = mkl_set_num_threads_local(0);
|
||||
struct Restore {
|
||||
int previous;
|
||||
~Restore() { static_cast<void>(mkl_set_num_threads_local(previous)); }
|
||||
} restore{previous};
|
||||
const int default_threads = mkl_get_max_threads();
|
||||
fesa::MklPardisoTangentSolver solver;
|
||||
for (int repeat = 0; repeat < 10; ++repeat) {
|
||||
auto correction = MakeVector({17.0});
|
||||
if (!solver.FactorizeFresh(MakeDenseCsr(1U, {2.0})).IsOk()) return false;
|
||||
if (!solver.SolveCorrection(MakeVector({4.0}), correction).IsOk() ||
|
||||
correction[0U] != 2.0) return false;
|
||||
if (!solver.FactorizeFresh(MakeDenseCsr(1U, {4.0})).IsOk()) return false;
|
||||
if (!solver.SolveCorrection(MakeVector({4.0}), correction).IsOk() ||
|
||||
correction[0U] != 1.0) return false;
|
||||
if (solver.SolveCorrection(MakeVector({
|
||||
std::numeric_limits<double>::infinity()}), correction).IsOk() ||
|
||||
correction[0U] != 1.0) return false;
|
||||
if (solver.FactorizeFresh(MakeDenseCsr(1U, {0.0})).IsOk()) return false;
|
||||
if (solver.SolveCorrection(MakeVector({4.0}), correction).IsOk() ||
|
||||
correction[0U] != 1.0) return false;
|
||||
if (mkl_get_max_threads() != default_threads ||
|
||||
mkl_set_num_threads_local(0) != 0) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
auto first = std::async(std::launch::async, worker);
|
||||
auto second = std::async(std::launch::async, worker);
|
||||
EXPECT_TRUE(first.get());
|
||||
EXPECT_TRUE(second.get());
|
||||
}
|
||||
|
||||
TEST(TangentSolver, SingleEquationScopeTransitionsBetweenRetainedSizes) {
|
||||
const int previous = mkl_set_num_threads_local(0);
|
||||
struct Restore {
|
||||
int previous;
|
||||
~Restore() { static_cast<void>(mkl_set_num_threads_local(previous)); }
|
||||
} restore{previous};
|
||||
const int default_threads = mkl_get_max_threads();
|
||||
fesa::MklPardisoTangentSolver solver;
|
||||
ASSERT_TRUE(solver.FactorizeFresh(MakeDenseCsr(1U, {2.0})).IsOk());
|
||||
auto single = MakeVector({0.0});
|
||||
ASSERT_TRUE(solver.SolveCorrection(MakeVector({4.0}), single).IsOk());
|
||||
EXPECT_DOUBLE_EQ(single[0U], 2.0);
|
||||
ASSERT_TRUE(solver.FactorizeFresh(MakeDenseCsr(2U, {2, 1, 0, 3})).IsOk());
|
||||
fesa::Vector pair{2U};
|
||||
ASSERT_TRUE(solver.SolveCorrection(MakeVector({6, 6}), pair).IsOk());
|
||||
EXPECT_NEAR(pair[0U], 2, 1e-14);
|
||||
EXPECT_NEAR(pair[1U], 2, 1e-14);
|
||||
EXPECT_EQ(mkl_get_max_threads(), default_threads);
|
||||
EXPECT_EQ(mkl_set_num_threads_local(0), 0);
|
||||
ASSERT_TRUE(solver.FactorizeFresh(MakeDenseCsr(1U, {4.0})).IsOk());
|
||||
ASSERT_TRUE(solver.SolveCorrection(MakeVector({8.0}), single).IsOk());
|
||||
EXPECT_DOUBLE_EQ(single[0U], 2.0);
|
||||
EXPECT_EQ(mkl_get_max_threads(), default_threads);
|
||||
EXPECT_EQ(mkl_set_num_threads_local(0), 0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user