The preconditioner export example..
This example depends on simple-solver.
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
std::string name)
{
std::ofstream stream{name};
std::cerr << "Writing " << name << std::endl;
}
template <typename Function>
auto try_generate(Function fun) -> decltype(fun())
{
decltype(fun()) result;
try {
result = fun();
std::cerr <<
"Error: " << err.
what() <<
'\n';
std::exit(-1);
}
return result;
}
int main(int argc, char* argv[])
{
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
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);
}));
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
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(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") {
ilu: no parameters
auto ilu = gko::as<gko::Composition<>>(try_generate([&] {
}));
matrix + ".ilu-l");
matrix + ".ilu-u");
} else if (precond == "parilu") {
parilu: iterations
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); }));
matrix + ".parilu" + output_suffix + "-l");
matrix + ".parilu" + output_suffix + "-u");
} else if (precond == "parilut") {
parilut: iterations, fill-in limit
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); }));
matrix + ".parilut" + output_suffix + "-l");
matrix + ".parilut" + output_suffix + "-u");
} else if (precond == "ilu-isai") {
ilu-isai: sparsity power
auto fact_factory =
int sparsity_power = 1;
if (argc >= 5) {
sparsity_power = std::stoi(argv[4]);
}
.with_factorization(fact_factory)
.with_sparsity_power(sparsity_power))
.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") {
parilu-isai: iterations, sparsity power
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));
.with_factorization(fact_factory)
.with_sparsity_power(sparsity_power))
.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
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));
.with_factorization(fact_factory)
.with_sparsity_power(sparsity_power))
.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(); }},
{"cuda",
[] {
0, gko::ReferenceExecutor::create());
}},
{"hip",
[] {
0, gko::ReferenceExecutor::create());
}},
{"dpcpp", [] {
0, gko::ReferenceExecutor::create());
}}};
std::string name)
{
std::ofstream stream{name};
std::cerr << "Writing " << name << std::endl;
}
template <typename Function>
auto try_generate(Function fun) -> decltype(fun())
{
decltype(fun()) result;
try {
result = fun();
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];
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") {
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(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([&] {
}));
matrix + ".ilu-l");
matrix + ".ilu-u");
} else if (precond == "parilu") {
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); }));
matrix + ".parilu" + output_suffix + "-l");
matrix + ".parilu" + output_suffix + "-u");
} else if (precond == "parilut") {
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); }));
matrix + ".parilut" + output_suffix + "-l");
matrix + ".parilut" + output_suffix + "-u");
} else if (precond == "ilu-isai") {
auto fact_factory =
int sparsity_power = 1;
if (argc >= 5) {
sparsity_power = std::stoi(argv[4]);
}
.with_factorization(fact_factory)
.with_sparsity_power(sparsity_power))
.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") {
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));
.with_factorization(fact_factory)
.with_sparsity_power(sparsity_power))
.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") {
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));
.with_factorization(fact_factory)
.with_sparsity_power(sparsity_power))
.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");
}
}