-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
301 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# Procedurally generate Matrix Market | ||
|
||
The `fast_matrix_market` write mechanism can write procedurally generated data. | ||
|
||
To make this process simpler, the `generator.hpp` header includes a method that can generate a coordinate Matrix Market file | ||
where each `row`, `column`, `value` triplet is individually generated using a *Callable*. | ||
|
||
# Usage | ||
|
||
```c++ | ||
#include <fast_matrix_market/app/generator.hpp> | ||
``` | ||
|
||
Create a *Callable* with the signature: | ||
```c++ | ||
void generate_tuple(int64_t coo_index, IT &row, IT &col, VT &value); | ||
``` | ||
where: | ||
* `coo_index` is an input parameter with the index of the tuple to be generated. | ||
* `row`, `col`, `value` are the output parameters defining the generated tuple. | ||
* `IT` is the integral type of the row and column indices, eg. `int64_t` or `int`. | ||
* `VT` is the value type, eg. `double` or `float`. | ||
Then call `fast_matrix_market::write_matrix_market_generated_triplet<IT, VT>` which takes the output stream, | ||
the header, number of nonzeros `nnz`, and the callable. | ||
The callable is called when a value of a tuple is needed, so eventually it will be called for every index in the half-open range [0, `nnz`). | ||
The calls may be out of order and in parallel. The callable must be thread safe. | ||
The Matrix Market `field` type is deduced from `VT`, or can be set to `pattern` in the header. | ||
### Example: Generate an identity matrix | ||
```c++ | ||
// #rows, #cols, and nnz | ||
const int64_t eye_rank = 10; | ||
fast_matrix_market::write_matrix_market_generated_triplet<int64_t, double>( | ||
output_stream, {eye_rank, eye_rank}, eye_rank, | ||
[](auto coo_index, auto& row, auto& col, auto& value) { | ||
row = coo_index; | ||
col = coo_index; | ||
value = 1; | ||
}); | ||
``` | ||
|
||
### Example: Generate a random matrix | ||
|
||
Generate a 100-by-100 matrix with 1000 randomized elements. | ||
```c++ | ||
void generate_random_tuple([[maybe_unused]] int64_t coo_index, int64_t &row, int64_t &col, double& value) { | ||
// The RNG is cheap to use but expensive to create and not thread safe. | ||
// Use thread_local to create one instance per thread. | ||
static thread_local std::mt19937 generator; | ||
// distribution objects are effectively optimized away | ||
std::uniform_int_distribution<int64_t> index_distribution(0, 99); | ||
std::uniform_real_distribution<double> value_distribution(0, 1); | ||
|
||
row = index_distribution(generator); | ||
col = index_distribution(generator); | ||
value = value_distribution(generator); | ||
} | ||
|
||
fast_matrix_market::write_matrix_market_generated_triplet<int64_t, double>( | ||
output_stream, {100, 100}, 1000, generate_random_tuple); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// Copyright (C) 2023 Adam Lugowski. All rights reserved. | ||
// Use of this source code is governed by the BSD 2-clause license found in the LICENSE.txt file. | ||
// SPDX-License-Identifier: BSD-2-Clause | ||
|
||
#include <sstream> | ||
|
||
#include "fmm_bench.hpp" | ||
#include <fast_matrix_market/app/generator.hpp> | ||
|
||
using VT = double; | ||
static int num_iterations = 3; | ||
|
||
/** | ||
* Write a generated identity matrix. | ||
*/ | ||
static void generate_eye(benchmark::State& state) { | ||
const int64_t eye_rank = 1 << 22; | ||
|
||
std::size_t num_bytes = 0; | ||
|
||
fast_matrix_market::write_options options; | ||
options.parallel_ok = true; | ||
options.num_threads = (int)state.range(0); | ||
|
||
for ([[maybe_unused]] auto _ : state) { | ||
std::ostringstream oss; | ||
fast_matrix_market::write_matrix_market_generated_triplet<int64_t, VT>( | ||
oss, {eye_rank, eye_rank}, eye_rank, | ||
[](auto coo_index, auto& row, auto& col, auto& value) { | ||
row = coo_index; | ||
col = coo_index; | ||
value = 1; | ||
}, options); | ||
|
||
num_bytes += oss.str().size(); | ||
benchmark::ClobberMemory(); | ||
} | ||
|
||
state.SetBytesProcessed((int64_t)num_bytes); | ||
} | ||
|
||
BENCHMARK(generate_eye)->Name("op:write/matrix:generated_eye/impl:FMM/lang:C++")->UseRealTime()->Iterations(num_iterations)->Apply(NumThreadsArgument); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// Copyright (C) 2023 Adam Lugowski. All rights reserved. | ||
// Use of this source code is governed by the BSD 2-clause license found in the LICENSE.txt file. | ||
// SPDX-License-Identifier: BSD-2-Clause | ||
|
||
#pragma once | ||
|
||
#include "../fast_matrix_market.hpp" | ||
|
||
namespace fast_matrix_market { | ||
/** | ||
* Format (row, col, value) triplets generated by a generator callable like this one: | ||
* [](auto coo_index, auto& row, auto& col, auto& value) { row = coo_index; col = coo_index; value = 1; } | ||
*/ | ||
template<typename IT, typename VT, typename LF, typename GEN_CALLABLE> | ||
class coo_independent_generator_formatter { | ||
public: | ||
explicit coo_independent_generator_formatter(LF lf, int64_t nnz, GEN_CALLABLE gen_callable) : | ||
line_formatter(lf), nnz(nnz), gen_callable(gen_callable) { | ||
if (nnz < 0) { | ||
throw invalid_argument("nnz cannot be negative."); | ||
} | ||
} | ||
|
||
[[nodiscard]] bool has_next() const { | ||
return next_chunk_offset < nnz; | ||
} | ||
|
||
class chunk { | ||
public: | ||
explicit chunk(LF lf, int64_t chunk_offset, int64_t chunk_nnz, GEN_CALLABLE gen_callable) : | ||
line_formatter(lf), chunk_offset(chunk_offset), chunk_nnz(chunk_nnz), gen_callable(gen_callable) { | ||
} | ||
|
||
std::string operator()() { | ||
std::string chunk; | ||
chunk.reserve(chunk_nnz*25); | ||
|
||
for (int64_t i = 0; i < chunk_nnz; ++i) { | ||
IT row, col; | ||
VT value; | ||
gen_callable(chunk_offset + i, row, col, value); | ||
chunk += line_formatter.coord_matrix(row, col, value); | ||
} | ||
|
||
return chunk; | ||
} | ||
|
||
LF line_formatter; | ||
int64_t chunk_offset; | ||
int64_t chunk_nnz; | ||
GEN_CALLABLE gen_callable; | ||
}; | ||
|
||
chunk next_chunk(const write_options& options) { | ||
auto chunk_size = std::min(options.chunk_size_values, (nnz - next_chunk_offset)); | ||
chunk c(line_formatter, next_chunk_offset, chunk_size, gen_callable); | ||
next_chunk_offset += chunk_size; | ||
return c; | ||
} | ||
|
||
protected: | ||
LF line_formatter; | ||
int64_t nnz; | ||
GEN_CALLABLE gen_callable; | ||
int64_t next_chunk_offset = 0; | ||
}; | ||
|
||
/** | ||
* Write generated triplets to a Matrix Market file. | ||
* | ||
* @tparam IT index type of generated row and column indices | ||
* @tparam VT value type of generated values | ||
* @tparam GEN_CALLABLE | ||
* @param os stream to write to | ||
* @param header header, use {row, col} syntax for just dimensions | ||
* @param nnz number of nonzeros in the generated MatrixMarket file | ||
* @param gen_callable a Callable that accepts the triplet index as an in parameter and row, column, value as out parameter | ||
* @param options | ||
*/ | ||
template <typename IT, typename VT, typename GEN_CALLABLE> | ||
void write_matrix_market_generated_triplet(std::ostream &os, | ||
matrix_market_header header, | ||
int64_t nnz, | ||
GEN_CALLABLE gen_callable, | ||
const write_options& options = {}) { | ||
header.nnz = nnz; | ||
|
||
header.object = matrix; | ||
if (header.field != pattern) { | ||
header.field = get_field_type((const VT *) nullptr); | ||
} | ||
header.format = coordinate; | ||
|
||
write_header(os, header, options); | ||
|
||
line_formatter<IT, VT> lf(header, options); | ||
auto formatter = coo_independent_generator_formatter<IT, VT, decltype(lf), decltype(gen_callable)>(lf, nnz, gen_callable); | ||
write_body(os, formatter, options); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters