Skip to content

Commit

Permalink
add near-symmetric symbolic LU to interface
Browse files Browse the repository at this point in the history
  • Loading branch information
upsj committed Oct 31, 2023
1 parent fbedc6d commit 0328da6
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 40 deletions.
25 changes: 17 additions & 8 deletions benchmark/solver/solver_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ DEFINE_bool(
rel_residual, false,
"Use relative residual instead of residual reduction stopping criterion");

DEFINE_string(
solvers, "cg",
"A comma-separated list of solvers to run. "
"Supported values are: bicgstab, bicg, cb_gmres_keep, "
"cb_gmres_reduce1, cb_gmres_reduce2, cb_gmres_integer, "
"cb_gmres_ireduce1, cb_gmres_ireduce2, cg, cgs, fcg, gmres, idr, "
"lower_trs, upper_trs, spd_direct, symm_direct, direct, overhead");
DEFINE_string(solvers, "cg",
"A comma-separated list of solvers to run. "
"Supported values are: bicgstab, bicg, cb_gmres_keep, "
"cb_gmres_reduce1, cb_gmres_reduce2, cb_gmres_integer, "
"cb_gmres_ireduce1, cb_gmres_ireduce2, cg, cgs, fcg, gmres, idr, "
"lower_trs, upper_trs, spd_direct, symm_direct, "
"near_symm_direct, direct, overhead");

DEFINE_uint32(
nrhs, 1,
Expand Down Expand Up @@ -246,7 +246,16 @@ std::unique_ptr<gko::LinOpFactory> generate_solver(
return gko::experimental::solver::Direct<etype, itype>::build()
.with_factorization(
gko::experimental::factorization::Lu<etype, itype>::build()
.with_symmetric_sparsity(true))
.with_symbolic_algorithm(gko::experimental::factorization::
symbolic_algorithm::symmetric))
.on(exec);
} else if (description == "near_symm_direct") {
return gko::experimental::solver::Direct<etype, itype>::build()
.with_factorization(
gko::experimental::factorization::Lu<etype, itype>::build()
.with_symbolic_algorithm(
gko::experimental::factorization::symbolic_algorithm::
near_symmetric))
.on(exec);
} else if (description == "direct") {
return gko::experimental::solver::Direct<etype, itype>::build()
Expand Down
35 changes: 35 additions & 0 deletions benchmark/sparse_blas/operations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,37 @@ class SymbolicLuOperation : public BenchmarkOperation {
};


class SymbolicLuNearSymmOperation : public BenchmarkOperation {
public:
explicit SymbolicLuNearSymmOperation(const Mtx* mtx) : mtx_{mtx}, result_{}
{}

std::pair<bool, double> validate() const override
{
return std::make_pair(
validate_symbolic_factorization(mtx_, result_.get()), 0.0);
}

gko::size_type get_flops() const override { return 0; }

gko::size_type get_memory() const override { return 0; }

void run() override
{
gko::factorization::symbolic_lu_near_symm(mtx_, result_);
}

void write_stats(json& object) override
{
object["factor_nonzeros"] = result_->get_num_stored_elements();
}

private:
const Mtx* mtx_;
std::unique_ptr<Mtx> result_;
};


class SymbolicCholeskyOperation : public BenchmarkOperation {
public:
explicit SymbolicCholeskyOperation(const Mtx* mtx, bool symmetric)
Expand Down Expand Up @@ -817,6 +848,10 @@ const std::map<std::string,
[](const Mtx* mtx) {
return std::make_unique<SymbolicLuOperation>(mtx);
}},
{"symbolic_lu_near_symm",
[](const Mtx* mtx) {
return std::make_unique<SymbolicLuNearSymmOperation>(mtx);
}},
{"symbolic_cholesky",
[](const Mtx* mtx) {
return std::make_unique<SymbolicCholeskyOperation>(mtx, false);
Expand Down
2 changes: 1 addition & 1 deletion benchmark/sparse_blas/sparse_blas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ using mat_data = gko::matrix_data<etype, itype>;
const char* operations_string =
"Comma-separated list of operations to be benchmarked. Can be "
"spgemm, spgeam, transpose, sort, is_sorted, generate_lookup, "
"lookup, symbolic_lu, symbolic_cholesky, "
"lookup, symbolic_lu, symbolic_lu_near_symm, symbolic_cholesky, "
"symbolic_cholesky_symmetric, reorder_rcm, "
#if GKO_HAVE_METIS
"reorder_nd, "
Expand Down
17 changes: 14 additions & 3 deletions core/factorization/lu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ GKO_REGISTER_OPERATION(factorize, lu_factorization::factorize);
GKO_REGISTER_HOST_OPERATION(symbolic_cholesky,
gko::factorization::symbolic_cholesky);
GKO_REGISTER_HOST_OPERATION(symbolic_lu, gko::factorization::symbolic_lu);
GKO_REGISTER_HOST_OPERATION(symbolic_lu_near_symm,
gko::factorization::symbolic_lu_near_symm);


} // namespace
Expand Down Expand Up @@ -95,12 +97,21 @@ std::unique_ptr<LinOp> Lu<ValueType, IndexType>::generate_impl(
const auto num_rows = mtx->get_size()[0];
std::unique_ptr<matrix_type> factors;
if (!parameters_.symbolic_factorization) {
if (parameters_.symmetric_sparsity) {
switch (parameters_.symbolic_algorithm) {
case symbolic_algorithm::general:
exec->run(make_symbolic_lu(mtx.get(), factors));
break;
case symbolic_algorithm::near_symmetric:
exec->run(make_symbolic_lu_near_symm(mtx.get(), factors));
break;
case symbolic_algorithm::symmetric: {
std::unique_ptr<gko::factorization::elimination_forest<IndexType>>
forest;
exec->run(make_symbolic_cholesky(mtx.get(), true, factors, forest));
} else {
exec->run(make_symbolic_lu(mtx.get(), factors));
break;
}
default:
GKO_INVALID_STATE("Invalid symbolic factorization algorithm");
}
} else {
const auto& symbolic = parameters_.symbolic_factorization;
Expand Down
30 changes: 25 additions & 5 deletions include/ginkgo/core/factorization/lu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,24 @@ namespace experimental {
namespace factorization {


enum class symbolic_algorithm {
/** An LU factorization algorithm that works on all matrices. */
general,
/**
* An LU factorization algorithm that works best on matrices with an almost
* symmetric sparsity pattern. It is correct for general matrices, but may
* use excessive amounts of memory and time.
*/
near_symmetric,
/**
* An LU factorization algorithm that works only on matrices with a
* symmetric sparsity pattern. Running it on a matrix with a non-symmetric
* sparsity pattern will likely lead to the application crashing.
*/
symmetric
};


/**
* Computes an LU factorization of a sparse matrix. This LinOpFactory returns a
* Factorization storing the L and U factors for the provided system matrix in
Expand Down Expand Up @@ -85,12 +103,14 @@ class Lu
GKO_FACTORY_PARAMETER_SCALAR(symbolic_factorization, nullptr);

/**
* If the system matrix has a symmetric sparsity pattern, set this flag
* to `true` to use a symbolic Cholesky factorization instead of a
* symbolic LU factorization to determine the sparsity pattern of L & U.
* This will most likely significantly reduce the generation runtime.
* If the symbolic factorization of the matrix is not provided to the
* factory, this parameter controls which algorithm will be used to
* compute it.
* @note Only use symbolic_factorization_algorithm::symmetric if you are
* sure your matrix has a symmetric sparsity pattern!
*/
bool GKO_FACTORY_PARAMETER_SCALAR(symmetric_sparsity, false);
symbolic_algorithm GKO_FACTORY_PARAMETER_SCALAR(
symbolic_algorithm, symbolic_algorithm::general);

/**
* The `system_matrix`, which will be given to this factory, must be
Expand Down
39 changes: 34 additions & 5 deletions reference/test/factorization/lu_kernels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,8 @@ TYPED_TEST(Lu, FactorizeSymmetricWorks)
auto factory =
gko::experimental::factorization::Lu<value_type,
index_type>::build()
.with_symmetric_sparsity(true)
.with_symbolic_algorithm(gko::experimental::factorization::
symbolic_algorithm::symmetric)
.on(this->ref);

auto lu = factory->generate(this->mtx);
Expand All @@ -288,10 +289,38 @@ TYPED_TEST(Lu, FactorizeNonsymmetricWorks)
using value_type = typename TestFixture::value_type;
using index_type = typename TestFixture::index_type;
this->forall_matrices([this] {
auto factory = gko::experimental::factorization::Lu<value_type,
index_type>::build()
.with_symmetric_sparsity(false)
.on(this->ref);
auto factory =
gko::experimental::factorization::Lu<value_type,
index_type>::build()
.with_symbolic_algorithm(gko::experimental::factorization::
symbolic_algorithm::general)
.on(this->ref);

auto lu = factory->generate(this->mtx);

GKO_ASSERT_MTX_EQ_SPARSITY(lu->get_combined(), this->mtx_lu);
GKO_ASSERT_MTX_NEAR(lu->get_combined(), this->mtx_lu,
15 * r<value_type>::value);
ASSERT_EQ(lu->get_storage_type(),
gko::experimental::factorization::storage_type::combined_lu);
ASSERT_EQ(lu->get_lower_factor(), nullptr);
ASSERT_EQ(lu->get_upper_factor(), nullptr);
ASSERT_EQ(lu->get_diagonal(), nullptr);
});
}


TYPED_TEST(Lu, FactorizeNearSymmetricWorks)
{
using value_type = typename TestFixture::value_type;
using index_type = typename TestFixture::index_type;
this->forall_matrices([this] {
auto factory =
gko::experimental::factorization::Lu<value_type,
index_type>::build()
.with_symbolic_algorithm(gko::experimental::factorization::
symbolic_algorithm::near_symmetric)
.on(this->ref);

auto lu = factory->generate(this->mtx);

Expand Down
4 changes: 3 additions & 1 deletion reference/test/solver/direct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ class Direct : public ::testing::Test {
.with_factorization(
gko::experimental::factorization::Lu<value_type,
index_type>::build()
.with_symmetric_sparsity(true))
.with_symbolic_algorithm(
gko::experimental::factorization::
symbolic_algorithm::symmetric))
.on(exec);
solver = factory->generate(mtx);
std::normal_distribution<gko::remove_complex<value_type>> dist(0, 1);
Expand Down
41 changes: 36 additions & 5 deletions test/factorization/lu_kernels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,14 +286,45 @@ TYPED_TEST(Lu, GenerateSymmWithUnknownSparsityIsEquivalentToRef)
using value_type = typename TestFixture::value_type;
using index_type = typename TestFixture::index_type;
this->forall_matrices([this] {
auto factory = gko::experimental::factorization::Lu<value_type,
index_type>::build()
.with_symmetric_sparsity(true)
.on(this->ref);
auto factory =
gko::experimental::factorization::Lu<value_type,
index_type>::build()
.with_symbolic_algorithm(gko::experimental::factorization::
symbolic_algorithm::symmetric)
.on(this->ref);
auto dfactory =
gko::experimental::factorization::Lu<value_type,
index_type>::build()
.with_symbolic_algorithm(gko::experimental::factorization::
symbolic_algorithm::symmetric)
.on(this->exec);

auto lu = factory->generate(this->mtx);
auto dlu = dfactory->generate(this->dmtx);

GKO_ASSERT_MTX_EQ_SPARSITY(lu->get_combined(), dlu->get_combined());
GKO_ASSERT_MTX_NEAR(lu->get_combined(), dlu->get_combined(),
r<value_type>::value);
});
}


TYPED_TEST(Lu, GenerateNearSymmWithUnknownSparsityIsEquivalentToRef)
{
using value_type = typename TestFixture::value_type;
using index_type = typename TestFixture::index_type;
this->forall_matrices([this] {
auto factory =
gko::experimental::factorization::Lu<value_type,
index_type>::build()
.with_symbolic_algorithm(gko::experimental::factorization::
symbolic_algorithm::near_symmetric)
.on(this->ref);
auto dfactory =
gko::experimental::factorization::Lu<value_type,
index_type>::build()
.with_symmetric_sparsity(true)
.with_symbolic_algorithm(gko::experimental::factorization::
symbolic_algorithm::near_symmetric)
.on(this->exec);

auto lu = factory->generate(this->mtx);
Expand Down
26 changes: 14 additions & 12 deletions test/solver/direct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,22 +93,24 @@ class Direct : public CommonTestFixture {
mtx = gko::read<matrix_type>(s_mtx, ref);
dmtx = gko::clone(exec, mtx);
const auto num_rows = mtx->get_size()[0];
factory =
solver_type::build()
.with_factorization(
factorization_type::build().with_symmetric_sparsity(true))
.with_num_rhs(static_cast<gko::size_type>(nrhs))
.on(ref);
factory = solver_type::build()
.with_factorization(
factorization_type::build().with_symbolic_algorithm(
gko::experimental::factorization::
symbolic_algorithm::symmetric))
.with_num_rhs(static_cast<gko::size_type>(nrhs))
.on(ref);
alpha = gen_mtx(1, 1);
beta = gen_mtx(1, 1);
input = gen_mtx(num_rows, nrhs);
output = gen_mtx(num_rows, nrhs);
dfactory =
solver_type::build()
.with_factorization(
factorization_type::build().with_symmetric_sparsity(true))
.with_num_rhs(static_cast<gko::size_type>(nrhs))
.on(exec);
dfactory = solver_type::build()
.with_factorization(
factorization_type::build().with_symbolic_algorithm(
gko::experimental::factorization::
symbolic_algorithm::symmetric))
.with_num_rhs(static_cast<gko::size_type>(nrhs))
.on(exec);
dalpha = gko::clone(exec, alpha);
dbeta = gko::clone(exec, beta);
dinput = gko::clone(exec, input);
Expand Down

0 comments on commit 0328da6

Please sign in to comment.