Ginkgo: The preconditioner-export program

| Ginkgo Generated from branch based on main. Ginkgo version 1.11.0 A numerical linear algebra library targeting many-core architectures

Loading...
Searching...
No Matches
The preconditioner-export program

The preconditioner export example.

This example depends on simple-solver.

Table of contents
Introduction About the example The commented program | Results Comments about programming and debugging The plain program

# Introduction

### About the example

This example shows how to explicitly generate and store preconditioners for a given matrix. It can also be used to inspect and debug the preconditioner generation.

# The commented program

void output(gko::ptr_param<const gko::WritableToMatrixData<double, int>> mtx,
std::string name)
{
std::ofstream stream{name};
std::cerr << "Writing " << name << std::endl;
gko::write(stream, mtx, gko::layout_type::coordinate);
}
template <typename Function>
auto try_generate(Function fun) -> decltype(fun())
{
decltype(fun()) result;
try {
result = fun();
} catch (const gko::Error& err) {
std::cerr << "Error: " << err.what() << '\n';
std::exit(-1);
}
return result;
}
int main(int argc, char* argv[])
{
gko::Error
The Error class is used to report exceptional behaviour in library functions.
Definition exception.hpp:57
gko::Error::what
virtual const char * what() const noexcept override
Returns a human-readable string with a more detailed description of the error.
Definition exception.hpp:74
gko::WritableToMatrixData
A LinOp implementing this interface can write its data to a matrix_data structure.
Definition lin_op.hpp:660
gko::ptr_param
This class is used for function parameters in the place of raw pointers.
Definition utils_helper.hpp:41
gko::layout_type::coordinate
@ coordinate
The matrix should be written as a sparse matrix in coordinate format.
Definition mtx_io.hpp:101
gko::write
void write(StreamType &&os, MatrixPtrType &&matrix, layout_type layout=detail::mtx_io_traits< std::remove_cv_t< detail::pointee< MatrixPtrType > > >::default_layout)
Writes a matrix into an output stream in matrix market format.
Definition mtx_io.hpp:299

print usage message

if (argc < 2 || executors.find(argv[1]) == executors.end()) {
std::cerr << "Usage: executable"
<< " <reference|omp|cuda|hip|dpcpp> [<matrix-file>] "
"[<jacobi|ilu|parilu|parilut|ilu-isai|parilu-isai|parilut-"
"isai] [<preconditioner args>]\n";
std::cerr << "Jacobi parameters: [<max-block-size>] [<accuracy>] "
"[<storage-optimization:auto|0|1|2>]\n";
std::cerr << "ParILU parameters: [<iteration-count>]\n";
std::cerr
<< "ParILUT parameters: [<iteration-count>] [<fill-in-limit>]\n";
std::cerr << "ILU-ISAI parameters: [<sparsity-power>]\n";
std::cerr << "ParILU-ISAI parameters: [<iteration-count>] "
"[<sparsity-power>]\n";
std::cerr << "ParILUT-ISAI parameters: [<iteration-count>] "
"[<fill-in-limit>] [<sparsity-power>]\n";
return -1;
}

generate executor based on first argument

auto exec = try_generate([&] { return executors.at(argv[1])(); });

set matrix and preconditioner name with default values

std::string matrix = argc < 3 ? "data/A.mtx" : argv[2];
std::string precond = argc < 4 ? "jacobi" : argv[3];

load matrix file into Csr format

auto mtx = gko::share(try_generate([&] {
std::ifstream mtx_stream{matrix};
if (!mtx_stream) {
throw GKO_STREAM_ERROR("Unable to open matrix file");
}
std::cerr << "Reading " << matrix << std::endl;
return gko::read<gko::matrix::Csr<>>(mtx_stream, exec);
}));
gko::read
std::unique_ptr< MatrixType > read(StreamType &&is, MatrixArgs &&... args)
Reads a matrix stored in matrix market format from an input stream.
Definition mtx_io.hpp:160
gko::share
detail::shared_type< OwningPointer > share(OwningPointer &&p)
Marks the object pointed to by p as shared.
Definition utils_helper.hpp:224

concatenate remaining arguments for filename

std::string output_suffix;
for (auto i = 4; i < argc; ++i) {
output_suffix = output_suffix + "-" + argv[i];
}

handle different preconditioners

if (precond == "jacobi") {

jacobi: max_block_size, accuracy, storage_optimization

auto factory_parameter = gko::preconditioner::Jacobi<>::build();
if (argc >= 5) {
factory_parameter.with_max_block_size(
static_cast<gko::uint32>(std::stoi(argv[4])));
}
if (argc >= 6) {
factory_parameter.with_accuracy(std::stod(argv[5]));
}
if (argc >= 7) {
factory_parameter.with_storage_optimization(
std::string{argv[6]} == "auto"
? gko::precision_reduction::autodetect()
: gko::precision_reduction(0, std::stoi(argv[6])));
}
auto factory = factory_parameter.on(exec);
auto jacobi = try_generate([&] { return factory->generate(mtx); });
output(jacobi, matrix + ".jacobi" + output_suffix);
} else if (precond == "ilu") {
gko::precision_reduction::autodetect
static constexpr precision_reduction autodetect() noexcept
Returns a special encoding which instructs the algorithm to automatically detect the best precision.
Definition types.hpp:314
gko::log::profile_event_category::factory
@ factory
LinOpFactory events.
Definition profiler_hook.hpp:32
gko
The Ginkgo namespace.
Definition abstract_factory.hpp:20
gko::uint32
std::uint32_t uint32
32-bit unsigned integral type.
Definition types.hpp:130
std
STL namespace.

ilu: no parameters

auto ilu = gko::as<gko::Composition<>>(try_generate([&] {
return gko::factorization::Ilu<>::build().on(exec)->generate(mtx);
}));
output(gko::as<gko::matrix::Csr<>>(ilu->get_operators()[0]),
matrix + ".ilu-l");
output(gko::as<gko::matrix::Csr<>>(ilu->get_operators()[1]),
matrix + ".ilu-u");
} else if (precond == "parilu") {
gko::matrix::Csr
CSR is a matrix format which stores only the nonzero coefficients by compressing each row of the matr...
Definition csr.hpp:126
gko::as
std::decay_t< T > * as(U *obj)
Performs polymorphic type conversion.
Definition utils_helper.hpp:307

parilu: iterations

auto factory_parameter = gko::factorization::ParIlu<>::build();
if (argc >= 5) {
factory_parameter.with_iterations(
static_cast<gko::size_type>(std::stoi(argv[4])));
}
auto factory = factory_parameter.on(exec);
auto ilu = gko::as<gko::Composition<>>(
try_generate([&] { return factory->generate(mtx); }));
output(gko::as<gko::matrix::Csr<>>(ilu->get_operators()[0]),
matrix + ".parilu" + output_suffix + "-l");
output(gko::as<gko::matrix::Csr<>>(ilu->get_operators()[1]),
matrix + ".parilu" + output_suffix + "-u");
} else if (precond == "parilut") {
gko::size_type
std::size_t size_type
Integral type used for allocation quantities.
Definition types.hpp:90

parilut: iterations, fill-in limit

auto factory_parameter = gko::factorization::ParIlut<>::build();
if (argc >= 5) {
factory_parameter.with_iterations(
static_cast<gko::size_type>(std::stoi(argv[4])));
}
if (argc >= 6) {
factory_parameter.with_fill_in_limit(std::stod(argv[5]));
}
auto factory = factory_parameter.on(exec);
auto ilut = gko::as<gko::Composition<>>(
try_generate([&] { return factory->generate(mtx); }));
output(gko::as<gko::matrix::Csr<>>(ilut->get_operators()[0]),
matrix + ".parilut" + output_suffix + "-l");
output(gko::as<gko::matrix::Csr<>>(ilut->get_operators()[1]),
matrix + ".parilut" + output_suffix + "-u");
} else if (precond == "ilu-isai") {

ilu-isai: sparsity power

auto fact_factory =
gko::share(gko::factorization::Ilu<>::build().on(exec));
int sparsity_power = 1;
if (argc >= 5) {
sparsity_power = std::stoi(argv[4]);
}
auto factory =
gko::preconditioner::Ilu<gko::preconditioner::LowerIsai<>,
gko::preconditioner::UpperIsai<>>::build()
.with_factorization(fact_factory)
.with_l_solver(gko::preconditioner::LowerIsai<>::build()
.with_sparsity_power(sparsity_power))
.with_u_solver(gko::preconditioner::UpperIsai<>::build()
.with_sparsity_power(sparsity_power))
.on(exec);
auto ilu_isai = try_generate([&] { return factory->generate(mtx); });
output(ilu_isai->get_l_solver()->get_approximate_inverse(),
matrix + ".ilu-isai" + output_suffix + "-l");
output(ilu_isai->get_u_solver()->get_approximate_inverse(),
matrix + ".ilu-isai" + output_suffix + "-u");
} else if (precond == "parilu-isai") {
gko::preconditioner::Ilu
The Incomplete LU (ILU) preconditioner solves the equation for a given lower triangular matrix L,...
Definition ilu.hpp:117

parilu-isai: iterations, sparsity power

auto fact_parameter = gko::factorization::ParIlu<>::build();
int sparsity_power = 1;
if (argc >= 5) {
fact_parameter.with_iterations(
static_cast<gko::size_type>(std::stoi(argv[4])));
}
if (argc >= 6) {
sparsity_power = std::stoi(argv[5]);
}
auto fact_factory = gko::share(fact_parameter.on(exec));
auto factory =
gko::preconditioner::Ilu<gko::preconditioner::LowerIsai<>,
gko::preconditioner::UpperIsai<>>::build()
.with_factorization(fact_factory)
.with_l_solver(gko::preconditioner::LowerIsai<>::build()
.with_sparsity_power(sparsity_power))
.with_u_solver(gko::preconditioner::UpperIsai<>::build()
.with_sparsity_power(sparsity_power))
.on(exec);
auto ilu_isai = try_generate([&] { return factory->generate(mtx); });
output(ilu_isai->get_l_solver()->get_approximate_inverse(),
matrix + ".parilu-isai" + output_suffix + "-l");
output(ilu_isai->get_u_solver()->get_approximate_inverse(),
matrix + ".parilu-isai" + output_suffix + "-u");
} else if (precond == "parilut-isai") {

parilut-isai: iterations, fill-in limit, sparsity power

auto fact_parameter = gko::factorization::ParIlut<>::build();
int sparsity_power = 1;
if (argc >= 5) {
fact_parameter.with_iterations(
static_cast<gko::size_type>(std::stoi(argv[4])));
}
if (argc >= 6) {
fact_parameter.with_fill_in_limit(std::stod(argv[5]));
}
if (argc >= 7) {
sparsity_power = std::stoi(argv[6]);
}
auto fact_factory = gko::share(fact_parameter.on(exec));
auto factory =
gko::preconditioner::Ilu<gko::preconditioner::LowerIsai<>,
gko::preconditioner::UpperIsai<>>::build()
.with_factorization(fact_factory)
.with_l_solver(gko::preconditioner::LowerIsai<>::build()
.with_sparsity_power(sparsity_power))
.with_u_solver(gko::preconditioner::UpperIsai<>::build()
.with_sparsity_power(sparsity_power))
.on(exec);
auto ilu_isai = try_generate([&] { return factory->generate(mtx); });
output(ilu_isai->get_l_solver()->get_approximate_inverse(),
matrix + ".parilut-isai" + output_suffix + "-l");
output(ilu_isai->get_u_solver()->get_approximate_inverse(),
matrix + ".parilut-isai" + output_suffix + "-u");
}
}

# Results

This is the expected output:

Usage: ./preconditioner-export <reference|omp|cuda|hip|dpcpp> [<matrix-file>] [<jacobi|ilu|parilu|parilut|ilu-isai|parilu-isai|parilut-isai] [<preconditioner args>]
Jacobi parameters: [<max-block-size>] [<accuracy>] [<storage-optimization:auto|0|1|2>]
ParILU parameters: [<iteration-count>]
ParILUT parameters: [<iteration-count>] [<fill-in-limit>]
ILU-ISAI parameters: [<sparsity-power>]
ParILU-ISAI parameters: [<iteration-count>] [<sparsity-power>]
ParILUT-ISAI parameters: [<iteration-count>] [<fill-in-limit>] [<sparsity-power>]

When specifying an executor:

Reading data/A.mtx
Writing data/A.mtx.jacobi

### Comments about programming and debugging

# The plain program

#include <fstream>
#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <ginkgo/ginkgo.hpp>
const std::map<std::string, std::function<std::shared_ptr<gko::Executor>()>>
executors{{"reference", [] { return gko::ReferenceExecutor::create(); }},
{"omp", [] { return gko::OmpExecutor::create(); }},
{"cuda",
[] {
return gko::CudaExecutor::create(
0, gko::ReferenceExecutor::create());
}},
{"hip",
[] {
return gko::HipExecutor::create(
0, gko::ReferenceExecutor::create());
}},
{"dpcpp", [] {
return gko::DpcppExecutor::create(
0, gko::ReferenceExecutor::create());
}}};
void output(gko::ptr_param<const gko::WritableToMatrixData<double, int>> mtx,
std::string name)
{
std::ofstream stream{name};
std::cerr << "Writing " << name << std::endl;
gko::write(stream, mtx, gko::layout_type::coordinate);
}
template <typename Function>
auto try_generate(Function fun) -> decltype(fun())
{
decltype(fun()) result;
try {
result = fun();
} catch (const gko::Error& err) {
std::cerr << "Error: " << err.what() << '\n';
std::exit(-1);
}
return result;
}
int main(int argc, char* argv[])
{
if (argc < 2 || executors.find(argv[1]) == executors.end()) {
std::cerr << "Usage: executable"
<< " <reference|omp|cuda|hip|dpcpp> [<matrix-file>] "
"[<jacobi|ilu|parilu|parilut|ilu-isai|parilu-isai|parilut-"
"isai] [<preconditioner args>]\n";
std::cerr << "Jacobi parameters: [<max-block-size>] [<accuracy>] "
"[<storage-optimization:auto|0|1|2>]\n";
std::cerr << "ParILU parameters: [<iteration-count>]\n";
std::cerr
<< "ParILUT parameters: [<iteration-count>] [<fill-in-limit>]\n";
std::cerr << "ILU-ISAI parameters: [<sparsity-power>]\n";
std::cerr << "ParILU-ISAI parameters: [<iteration-count>] "
"[<sparsity-power>]\n";
std::cerr << "ParILUT-ISAI parameters: [<iteration-count>] "
"[<fill-in-limit>] [<sparsity-power>]\n";
return -1;
}
auto exec = try_generate([&] { return executors.at(argv[1])(); });
std::string matrix = argc < 3 ? "data/A.mtx" : argv[2];
std::string precond = argc < 4 ? "jacobi" : argv[3];
auto mtx = gko::share(try_generate([&] {
std::ifstream mtx_stream{matrix};
if (!mtx_stream) {
throw GKO_STREAM_ERROR("Unable to open matrix file");
}
std::cerr << "Reading " << matrix << std::endl;
return gko::read<gko::matrix::Csr<>>(mtx_stream, exec);
}));
std::string output_suffix;
for (auto i = 4; i < argc; ++i) {
output_suffix = output_suffix + "-" + argv[i];
}
if (precond == "jacobi") {
auto factory_parameter = gko::preconditioner::Jacobi<>::build();
if (argc >= 5) {
factory_parameter.with_max_block_size(
static_cast<gko::uint32>(std::stoi(argv[4])));
}
if (argc >= 6) {
factory_parameter.with_accuracy(std::stod(argv[5]));
}
if (argc >= 7) {
factory_parameter.with_storage_optimization(
std::string{argv[6]} == "auto"
? gko::precision_reduction::autodetect()
: gko::precision_reduction(0, std::stoi(argv[6])));
}
auto factory = factory_parameter.on(exec);
auto jacobi = try_generate([&] { return factory->generate(mtx); });
output(jacobi, matrix + ".jacobi" + output_suffix);
} else if (precond == "ilu") {
auto ilu = gko::as<gko::Composition<>>(try_generate([&] {
return gko::factorization::Ilu<>::build().on(exec)->generate(mtx);
}));
output(gko::as<gko::matrix::Csr<>>(ilu->get_operators()[0]),
matrix + ".ilu-l");
output(gko::as<gko::matrix::Csr<>>(ilu->get_operators()[1]),
matrix + ".ilu-u");
} else if (precond == "parilu") {
auto factory_parameter = gko::factorization::ParIlu<>::build();
if (argc >= 5) {
factory_parameter.with_iterations(
static_cast<gko::size_type>(std::stoi(argv[4])));
}
auto factory = factory_parameter.on(exec);
auto ilu = gko::as<gko::Composition<>>(
try_generate([&] { return factory->generate(mtx); }));
output(gko::as<gko::matrix::Csr<>>(ilu->get_operators()[0]),
matrix + ".parilu" + output_suffix + "-l");
output(gko::as<gko::matrix::Csr<>>(ilu->get_operators()[1]),
matrix + ".parilu" + output_suffix + "-u");
} else if (precond == "parilut") {
auto factory_parameter = gko::factorization::ParIlut<>::build();
if (argc >= 5) {
factory_parameter.with_iterations(
static_cast<gko::size_type>(std::stoi(argv[4])));
}
if (argc >= 6) {
factory_parameter.with_fill_in_limit(std::stod(argv[5]));
}
auto factory = factory_parameter.on(exec);
auto ilut = gko::as<gko::Composition<>>(
try_generate([&] { return factory->generate(mtx); }));
output(gko::as<gko::matrix::Csr<>>(ilut->get_operators()[0]),
matrix + ".parilut" + output_suffix + "-l");
output(gko::as<gko::matrix::Csr<>>(ilut->get_operators()[1]),
matrix + ".parilut" + output_suffix + "-u");
} else if (precond == "ilu-isai") {
auto fact_factory =
gko::share(gko::factorization::Ilu<>::build().on(exec));
int sparsity_power = 1;
if (argc >= 5) {
sparsity_power = std::stoi(argv[4]);
}
auto factory =
gko::preconditioner::Ilu<gko::preconditioner::LowerIsai<>,
gko::preconditioner::UpperIsai<>>::build()
.with_factorization(fact_factory)
.with_l_solver(gko::preconditioner::LowerIsai<>::build()
.with_sparsity_power(sparsity_power))
.with_u_solver(gko::preconditioner::UpperIsai<>::build()
.with_sparsity_power(sparsity_power))
.on(exec);
auto ilu_isai = try_generate([&] { return factory->generate(mtx); });
output(ilu_isai->get_l_solver()->get_approximate_inverse(),
matrix + ".ilu-isai" + output_suffix + "-l");
output(ilu_isai->get_u_solver()->get_approximate_inverse(),
matrix + ".ilu-isai" + output_suffix + "-u");
} else if (precond == "parilu-isai") {
auto fact_parameter = gko::factorization::ParIlu<>::build();
int sparsity_power = 1;
if (argc >= 5) {
fact_parameter.with_iterations(
static_cast<gko::size_type>(std::stoi(argv[4])));
}
if (argc >= 6) {
sparsity_power = std::stoi(argv[5]);
}
auto fact_factory = gko::share(fact_parameter.on(exec));
auto factory =
gko::preconditioner::Ilu<gko::preconditioner::LowerIsai<>,
gko::preconditioner::UpperIsai<>>::build()
.with_factorization(fact_factory)
.with_l_solver(gko::preconditioner::LowerIsai<>::build()
.with_sparsity_power(sparsity_power))
.with_u_solver(gko::preconditioner::UpperIsai<>::build()
.with_sparsity_power(sparsity_power))
.on(exec);
auto ilu_isai = try_generate([&] { return factory->generate(mtx); });
output(ilu_isai->get_l_solver()->get_approximate_inverse(),
matrix + ".parilu-isai" + output_suffix + "-l");
output(ilu_isai->get_u_solver()->get_approximate_inverse(),
matrix + ".parilu-isai" + output_suffix + "-u");
} else if (precond == "parilut-isai") {
auto fact_parameter = gko::factorization::ParIlut<>::build();
int sparsity_power = 1;
if (argc >= 5) {
fact_parameter.with_iterations(
static_cast<gko::size_type>(std::stoi(argv[4])));
}
if (argc >= 6) {
fact_parameter.with_fill_in_limit(std::stod(argv[5]));
}
if (argc >= 7) {
sparsity_power = std::stoi(argv[6]);
}
auto fact_factory = gko::share(fact_parameter.on(exec));
auto factory =
gko::preconditioner::Ilu<gko::preconditioner::LowerIsai<>,
gko::preconditioner::UpperIsai<>>::build()
.with_factorization(fact_factory)
.with_l_solver(gko::preconditioner::LowerIsai<>::build()
.with_sparsity_power(sparsity_power))
.with_u_solver(gko::preconditioner::UpperIsai<>::build()
.with_sparsity_power(sparsity_power))
.on(exec);
auto ilu_isai = try_generate([&] { return factory->generate(mtx); });
output(ilu_isai->get_l_solver()->get_approximate_inverse(),
matrix + ".parilut-isai" + output_suffix + "-l");
output(ilu_isai->get_u_solver()->get_approximate_inverse(),
matrix + ".parilut-isai" + output_suffix + "-u");
}
}
gko::CudaExecutor::create
static std::shared_ptr< CudaExecutor > create(int device_id, std::shared_ptr< Executor > master, bool device_reset, allocation_mode alloc_mode=default_cuda_alloc_mode, CUstream_st *stream=nullptr)
Creates a new CudaExecutor.
gko::DpcppExecutor::create
static std::shared_ptr< DpcppExecutor > create(int device_id, std::shared_ptr< Executor > master, std::string device_type="all", dpcpp_queue_property property=dpcpp_queue_property::in_order)
Creates a new DpcppExecutor.
gko::HipExecutor::create
static std::shared_ptr< HipExecutor > create(int device_id, std::shared_ptr< Executor > master, bool device_reset, allocation_mode alloc_mode=default_hip_alloc_mode, CUstream_st *stream=nullptr)
Creates a new HipExecutor.
gko::OmpExecutor::create
static std::shared_ptr< OmpExecutor > create(std::shared_ptr< CpuAllocatorBase > alloc=std::make_shared< CpuAllocator >())
Creates a new OmpExecutor.
Definition executor.hpp:1396