Files
workinf_Blender_Wasm/blender-5.2.0/extern/mantaflow/helper/util/rcmatrix.h
2026-08-12 04:47:48 -04:00

1049 lines
27 KiB
C++

//
// Helper matrix class, RCMatrix.h
// Required for PD optimizations (guiding)
// Thanks to Ryoichi Ando, and Robert Bridson
//
#ifndef RCMATRIX3_H
#define RCMATRIX3_H
#include <iterator>
#include <cassert>
#include <vector>
#include <fstream>
// index type
#define int_index long long
// link to omp & tbb for now
#if OPENMP == 1 || TBB == 1
# define MANTA_ENABLE_PARALLEL 1
// allow the preconditioner to be computed in parallel? (can lead to slightly non-deterministic
// results)
# define MANTA_ENABLE_PARALLEL_PC 0
#else
# define MANTA_ENABLE_PARALLEL 0
# define MANTA_ENABLE_PARALLEL_PC 0
#endif
#if MANTA_ENABLE_PARALLEL == 1
# include <thread>
# include <algorithm>
static const int manta_num_threads = std::thread::hardware_concurrency();
// For clang
# define parallel_for(total_size) \
{ \
int_index parallel_array_size = (total_size); \
std::vector<std::thread> threads(manta_num_threads); \
for (int thread_number = 0; thread_number < manta_num_threads; thread_number++) { \
threads[thread_number] = std::thread([&](int_index parallel_array_size, int_index thread_number ) { \
for( int_index parallel_index=thread_number; parallel_index < parallel_array_size; parallel_index += manta_num_threads ) {
# define parallel_end \
} \
},parallel_array_size,thread_number); \
} \
for (auto &thread : threads) \
thread.join(); \
}
# define parallel_block \
{ \
std::vector<std::thread> threads; \
{
# define do_parallel threads.push_back( std::thread([&]() {
# define do_end \
} ) );
# define block_end \
} \
for (auto &thread : threads) { \
thread.join(); \
} \
}
#else
# define parallel_for(size) \
{ \
int thread_number = 0; \
int_index parallel_index = 0; \
for (int_index parallel_index = 0; parallel_index < (int_index)size; parallel_index++) {
# define parallel_end \
} \
thread_number = parallel_index = 0; \
}
# define parallel_block
# define do_parallel
# define do_end
# define block_end
#endif
#include "vectorbase.h"
namespace Manta {
static const unsigned default_expected_none_zeros = 7;
template<class N, class T> struct RCMatrix {
struct RowEntry {
std::vector<N> index;
std::vector<T> value;
};
RCMatrix() : n(0), expected_none_zeros(default_expected_none_zeros)
{
}
RCMatrix(N size, N expected_none_zeros = default_expected_none_zeros)
: n(0), expected_none_zeros(expected_none_zeros)
{
resize(size);
}
RCMatrix(const RCMatrix &m) : n(0), expected_none_zeros(default_expected_none_zeros)
{
init(m);
}
RCMatrix &operator=(const RCMatrix &m)
{
expected_none_zeros = m.expected_none_zeros;
init(m);
return *this;
}
RCMatrix &operator=(RCMatrix &&m)
{
matrix = m.matrix;
offsets = m.offsets;
expected_none_zeros = m.expected_none_zeros;
n = m.n;
m.n = 0;
m.matrix.clear();
m.offsets.clear();
return *this;
}
RCMatrix(RCMatrix &&m)
: n(m.n), expected_none_zeros(m.expected_none_zeros), matrix(m.matrix), offsets(m.offsets)
{
m.n = 0;
m.matrix.clear();
m.offsets.clear();
}
void init(const RCMatrix &m)
{
expected_none_zeros = m.expected_none_zeros;
resize(m.n);
parallel_for(n)
{
N i = parallel_index;
if (m.matrix[i]) {
alloc_row(i);
matrix[i]->index = m.matrix[i]->index;
matrix[i]->value = m.matrix[i]->value;
}
else {
dealloc_row(i);
}
}
parallel_end
}
~RCMatrix()
{
clear();
}
void clear()
{
for (N i = 0; i < n; i++) {
dealloc_row(i);
matrix[i] = nullptr;
if (offsets.size())
offsets[i] = 0;
}
};
bool empty(N i) const
{
return matrix[i] == nullptr;
}
N row_nonzero_size(N i) const
{
return matrix[i] == nullptr ? 0 : matrix[i]->index.size();
}
void resize(N size, N expected_none_zeros = 0)
{
if (!expected_none_zeros) {
expected_none_zeros = this->expected_none_zeros;
}
if (n > size) {
// Shrinking
for (N i = size ? size - 1 : 0; i < n; i++)
dealloc_row(i);
matrix.resize(size);
}
else if (n < size) {
// Expanding
matrix.resize(size);
for (N i = n; i < size; i++) {
matrix[i] = nullptr;
if (offsets.size())
offsets[i] = 0;
}
}
n = size;
}
void alloc_row(N i)
{
assert(i < n);
if (!matrix[i]) {
matrix[i] = new RowEntry;
matrix[i]->index.reserve(expected_none_zeros);
matrix[i]->value.reserve(expected_none_zeros);
if (offsets.size())
offsets[i] = 0;
}
}
void dealloc_row(N i)
{
assert(i < n);
if (matrix[i]) {
if (offsets.empty() || !offsets[i])
delete matrix[i];
matrix[i] = nullptr;
if (offsets.size())
offsets[i] = 0;
}
}
T operator()(N i, N j) const
{
assert(i < n);
for (Iterator it = row_begin(i); it; ++it) {
if (it.index() == j)
return it.value();
}
return T(0.0);
}
void add_to_element_checked(N i, N j, T val)
{
if ((i < 0) || (j < 0) || (i >= n) || (j >= n))
return;
add_to_element(i, j, val);
}
void add_to_element(N i, N j, T increment_value)
{
if (std::abs(increment_value) > VECTOR_EPSILON) {
assert(i < n);
assert(offsets.empty() || offsets[i] == 0);
alloc_row(i);
std::vector<N> &index = matrix[i]->index;
std::vector<T> &value = matrix[i]->value;
for (N k = 0; k < (N)index.size(); ++k) {
if (index[k] == j) {
value[k] += increment_value;
return;
}
else if (index[k] > j) {
index.insert(index.begin() + k, j);
value.insert(value.begin() + k, increment_value);
return;
}
}
index.push_back(j);
value.push_back(increment_value);
}
}
void set_element(N i, N j, T v)
{
if (std::abs(v) > VECTOR_EPSILON) {
assert(i < n);
assert(offsets.empty() || offsets[i] == 0);
alloc_row(i);
std::vector<N> &index = matrix[i]->index;
std::vector<T> &value = matrix[i]->value;
for (N k = 0; k < (N)index.size(); ++k) {
if (index[k] == j) {
value[k] = v;
return;
}
else if (index[k] > j) {
index.insert(index.begin() + k, j);
value.insert(value.begin() + k, v);
return;
}
}
index.push_back(j);
value.push_back(v);
}
}
// Make sure that j is the biggest column in the row, no duplication allowed
void fix_element(N i, N j, T v)
{
if (std::abs(v) > VECTOR_EPSILON) {
assert(i < n);
assert(offsets.empty() || offsets[i] == 0);
alloc_row(i);
std::vector<N> &index = matrix[i]->index;
std::vector<T> &value = matrix[i]->value;
index.push_back(j);
value.push_back(v);
}
}
int_index trim_zero_entries(double e = VECTOR_EPSILON)
{
std::vector<int_index> deleted_entries(n, 0);
parallel_for(n)
{
N i = parallel_index;
if (matrix[i]) {
std::vector<N> &index = matrix[i]->index;
std::vector<T> &value = matrix[i]->value;
N head = 0;
N k = 0;
for (k = 0; k < index.size(); ++k) {
if (std::abs(value[k]) > e) {
index[head] = index[k];
value[head] = value[k];
++head;
}
}
if (head != k) {
index.erase(index.begin() + head, index.end());
value.erase(value.begin() + head, value.end());
deleted_entries[i] += k - head;
}
if (!offsets.size() && !head) {
remove_row(i);
}
}
}
parallel_end
//
int_index sum_deleted(0);
for (int_index i = 0; i < n; i++)
sum_deleted += deleted_entries[i];
return sum_deleted;
}
void remove_reference(N i)
{
if (offsets.size() && offsets[i] && matrix[i]) {
RowEntry *save = matrix[i];
matrix[i] = new RowEntry;
*matrix[i] = *save;
for (N &index : matrix[i]->index)
index += offsets[i];
offsets[i] = 0;
}
}
void remove_row(N i)
{
dealloc_row(i);
}
bool is_symmetric(double e = VECTOR_EPSILON) const
{
std::vector<bool> flags(n, true);
parallel_for(n)
{
N i = parallel_index;
bool flag = true;
for (Iterator it = row_begin(i); it; ++it) {
N index = it.index();
T value = it.value();
if (std::abs(value) > e) {
bool found_entry = false;
for (Iterator it_i = row_begin(index); it_i; ++it_i) {
if (it_i.index() == i) {
found_entry = true;
if (std::abs(value - it_i.value()) > e) {
flag = false;
break;
}
}
}
if (!found_entry)
flag = false;
if (!flag)
break;
}
}
flags[i] = flag;
}
parallel_end for (N i = 0; i < matrix.size(); ++i)
{
if (!flags[i])
return false;
}
return true;
}
void expand()
{
if (offsets.empty())
return;
for (N i = 1; i < n; i++) {
if (offsets[i]) {
RowEntry *ref = matrix[i];
matrix[i] = new RowEntry;
*matrix[i] = *ref;
for (N j = 0; j < (N)matrix[i]->index.size(); j++) {
matrix[i]->index[j] += offsets[i];
}
}
}
offsets.resize(0);
}
N column(N i) const
{
return empty(i) ? 0 : row_begin(i, row_nonzero_size(i) - 1).index();
}
N getColumnSize() const
{
N max_column(0);
auto column = [&](N i) {
N max_column(0);
for (Iterator it = row_begin(i); it; ++it)
max_column = std::max(max_column, it.index());
return max_column + 1;
};
for (N i = 0; i < n; i++)
max_column = std::max(max_column, column(i));
return max_column;
}
N getNonzeroSize() const
{
N nonzeros(0);
for (N i = 0; i < n; ++i) {
nonzeros += row_nonzero_size(i);
}
return nonzeros;
}
class Iterator : std::iterator<std::input_iterator_tag, T> {
public:
Iterator(const RowEntry *rowEntry, N k, N offset) : rowEntry(rowEntry), k(k), offset(offset)
{
}
operator bool() const
{
return rowEntry != nullptr && k < (N)rowEntry->index.size();
}
Iterator &operator++()
{
++k;
return *this;
}
T value() const
{
return rowEntry->value[k];
}
N index() const
{
return rowEntry->index[k] + offset;
}
N index_raw() const
{
return rowEntry->index[k];
}
N size() const
{
return rowEntry == nullptr ? 0 : rowEntry->index.size();
}
protected:
const RowEntry *rowEntry;
N k, offset;
};
Iterator row_begin(N n, N k = 0) const
{
return Iterator(matrix[n], k, offsets.size() ? offsets[n] : 0);
}
class DynamicIterator : public Iterator {
public:
DynamicIterator(RowEntry *rowEntry, N k, N offset)
: rowEntry(rowEntry), Iterator(rowEntry, k, offset)
{
}
void setValue(T value)
{
rowEntry->value[Iterator::k] = value;
}
void setIndex(N index)
{
rowEntry->index[Iterator::k] = index;
}
protected:
RowEntry *rowEntry;
};
DynamicIterator dynamic_row_begin(N n, N k = 0)
{
N offset = offsets.size() ? offsets[n] : 0;
if (offset) {
printf("---- Warning ----\n");
printf("Dynamic iterator is not allowed for referenced rows.\n");
printf("You should be very careful otherwise this causes some bugs.\n");
printf(
"We encourage you that you convert this row into a raw format, then loop over it...\n");
printf("-----------------\n");
exit(0);
}
return DynamicIterator(matrix[n], k, offset);
}
RCMatrix transpose(N rowsize = 0,
unsigned expected_none_zeros = default_expected_none_zeros) const
{
if (!rowsize)
rowsize = getColumnSize();
RCMatrix result(rowsize, expected_none_zeros);
for (N i = 0; i < n; i++) {
for (Iterator it = row_begin(i); it; ++it)
result.fix_element(it.index(), i, it.value());
}
return result;
}
RCMatrix getKtK() const
{
RCMatrix m = transpose();
RCMatrix result(n, expected_none_zeros);
// Run in parallel
parallel_for(result.n)
{
N i = parallel_index;
for (Iterator it_A = m.row_begin(i); it_A; ++it_A) {
N j = it_A.index();
assert(j < n);
T a = it_A.value();
if (std::abs(a) > VECTOR_EPSILON) {
for (Iterator it_B = row_begin(j); it_B; ++it_B) {
// result.add_to_element(i,it_B.index(),it_B.value()*a);
double value = it_B.value() * a;
if (std::abs(value) > VECTOR_EPSILON)
result.add_to_element(i, it_B.index(), value);
}
}
}
}
parallel_end return result;
}
RCMatrix operator*(const RCMatrix &m) const
{
RCMatrix result(n, expected_none_zeros);
// Run in parallel
parallel_for(result.n)
{
N i = parallel_index;
for (Iterator it_A = row_begin(i); it_A; ++it_A) {
N j = it_A.index();
assert(j < m.n);
T a = it_A.value();
if (std::abs(a) > VECTOR_EPSILON) {
for (Iterator it_B = m.row_begin(j); it_B; ++it_B) {
// result.add_to_element(i,it_B.index(),it_B.value()*a);
double value = it_B.value() * a;
if (std::abs(value) > VECTOR_EPSILON)
result.add_to_element(i, it_B.index(), value);
}
}
}
}
parallel_end return result;
}
RCMatrix sqrt() const
{
RCMatrix result(n, expected_none_zeros);
// Run in parallel
parallel_for(result.n)
{
N i = parallel_index;
for (Iterator it_A = row_begin(i); it_A; ++it_A) {
N j = it_A.index();
result.set_element(i, j, std::sqrt(it_A.value()));
}
}
parallel_end return result;
}
RCMatrix operator*(const double k) const
{
RCMatrix result(n, expected_none_zeros);
// Run in parallel
parallel_for(result.n)
{
N i = parallel_index;
for (Iterator it_A = row_begin(i); it_A; ++it_A) {
N j = it_A.index();
result.add_to_element(i, j, it_A.value() * k);
}
}
parallel_end return result;
}
RCMatrix applyKernel(const RCMatrix &kernel, const int nx, const int ny) const
{
RCMatrix result(n, expected_none_zeros);
// find center position of kernel (half of kernel size)
int kCols = kernel.n, kRows = kernel.n, rows = nx, cols = ny;
int kCenterX = kCols / 2;
int kCenterY = kRows / 2;
// Run in parallel
parallel_for(result.n)
{
N i = parallel_index;
if (i >= rows)
break;
for (Iterator it_A = row_begin(i); it_A; ++it_A) {
N j = it_A.index();
if (j >= cols)
break;
for (int m = 0; m < kRows; ++m) { // kernel rows
int mm = kRows - 1 - m; // row index of flipped kernel
for (int n = 0; n < kCols; ++n) { // kernel columns
int nn = kCols - 1 - n; // column index of flipped kernel
// index of input signal, used for checking boundary
int ii = i + (m - kCenterY);
int jj = j + (n - kCenterX);
// ignore input samples which are out of bound
if (ii >= 0 && ii < rows && jj >= 0 && jj < cols)
result.add_to_element(i, j, (*this)(ii, jj) * kernel(mm, nn));
}
}
}
}
parallel_end return result;
}
RCMatrix applyHorizontalKernel(const RCMatrix &kernel, const int nx, const int ny) const
{
RCMatrix result(n, expected_none_zeros);
// find center position of kernel (half of kernel size)
int kCols = kernel.n, kRows = 1, rows = nx, cols = ny;
int kCenterX = kCols / 2;
int kCenterY = kRows / 2;
// Run in parallel
parallel_for(result.n)
{
N i = parallel_index;
if (i >= rows)
break;
for (Iterator it_A = row_begin(i); it_A; ++it_A) {
N j = it_A.index();
if (j >= cols)
break;
for (int m = 0; m < kRows; ++m) { // kernel rows
int mm = kRows - 1 - m; // row index of flipped kernel
for (int n = 0; n < kCols; ++n) { // kernel columns
int nn = kCols - 1 - n; // column index of flipped kernel
// index of input signal, used for checking boundary
int ii = i + (m - kCenterY);
int jj = j + (n - kCenterX);
// ignore input samples which are out of bound
if (ii >= 0 && ii < rows && jj >= 0 && jj < cols)
result.add_to_element(i, j, (*this)(ii, jj) * kernel(mm, nn));
}
}
}
}
parallel_end return result;
}
RCMatrix applyVerticalKernel(const RCMatrix &kernel, const int nx, const int ny) const
{
RCMatrix result(n, expected_none_zeros);
// find center position of kernel (half of kernel size)
int kCols = 1, kRows = kernel.n, rows = nx, cols = ny;
int kCenterX = kCols / 2;
int kCenterY = kRows / 2;
// Run in parallel
parallel_for(result.n)
{
N i = parallel_index;
if (i >= rows)
break;
for (Iterator it_A = row_begin(i); it_A; ++it_A) {
N j = it_A.index();
if (j >= cols)
break;
for (int m = 0; m < kRows; ++m) { // kernel rows
int mm = kRows - 1 - m; // row index of flipped kernel
for (int n = 0; n < kCols; ++n) { // kernel columns
int nn = kCols - 1 - n; // column index of flipped kernel
// index of input signal, used for checking boundary
int ii = i + (m - kCenterY);
int jj = j + (n - kCenterX);
// ignore input samples which are out of bound
if (ii >= 0 && ii < rows && jj >= 0 && jj < cols)
result.add_to_element(i, j, (*this)(ii, jj) * kernel(mm, nn));
}
}
}
}
parallel_end return result;
}
RCMatrix applySeparableKernel(const RCMatrix &kernelH,
const RCMatrix &kernelV,
const int nx,
const int ny) const
{
return applyHorizontalKernel(kernelH, nx, ny).applyVerticalKernel(kernelV, nx, ny);
}
RCMatrix applySeparableKernelTwice(const RCMatrix &kernelH,
const RCMatrix &kernelV,
const int nx,
const int ny) const
{
return applySeparableKernel(kernelH, kernelV, nx, ny)
.applySeparableKernel(kernelH, kernelV, nx, ny);
}
std::vector<T> operator*(const std::vector<T> &rhs) const
{
std::vector<T> result(n, 0.0);
multiply(rhs, result);
return result;
}
void multiply(const std::vector<T> &rhs, std::vector<T> &result) const
{
result.resize(n);
for (N i = 0; i < n; i++) {
T new_value = 0.0;
for (Iterator it = row_begin(i); it; ++it) {
N j_index = it.index();
assert(j_index < rhs.size());
new_value += rhs[j_index] * it.value();
}
result[i] = new_value;
}
}
RCMatrix operator+(const RCMatrix &m) const
{
RCMatrix A(*this);
return std::move(A.add(m));
}
RCMatrix &add(const RCMatrix &m)
{
if (m.n > n)
resize(m.n);
parallel_for(m.n)
{
N i = parallel_index;
for (Iterator it = m.row_begin(i); it; ++it) {
add_to_element(i, it.index(), it.value());
}
}
parallel_end return *this;
}
RCMatrix operator-(const RCMatrix &m) const
{
RCMatrix A(*this);
return std::move(A.sub(m));
}
RCMatrix &sub(const RCMatrix &m)
{
if (m.n > n)
resize(m.n);
parallel_for(m.n)
{
N i = parallel_index;
for (Iterator it = m.row_begin(i); it; ++it) {
add_to_element(i, it.index(), -it.value());
}
}
parallel_end return *this;
}
RCMatrix &replace(const RCMatrix &m, int rowInd, int colInd)
{
if (m.n > n)
resize(m.n);
parallel_for(m.n)
{
N i = parallel_index;
for (Iterator it = m.row_begin(i); it; ++it) {
set_element(i + rowInd, it.index() + colInd, it.value());
}
}
parallel_end return *this;
}
Real max_residual(const std::vector<T> &lhs, const std::vector<T> &rhs) const
{
std::vector<T> r = operator*(lhs);
Real max_residual = 0.0;
for (N i = 0; i < rhs.size(); i++) {
if (!empty(i))
max_residual = std::max(max_residual, std::abs(r[i] - rhs[i]));
}
return max_residual;
}
std::vector<T> residual_vector(const std::vector<T> &lhs, const std::vector<T> &rhs) const
{
std::vector<T> result = operator*(lhs);
assert(result.size() == rhs.size());
for (N i = 0; i < result.size(); i++) {
result[i] = std::abs(result[i] - rhs[i]);
}
return result;
}
T norm() const
{
T result(0.0);
for (N i = 0; i < n; ++i) {
for (Iterator it = row_begin(i); it; ++it) {
result = std::max(result, std::abs(it.value()));
}
}
return result;
}
T norm_L2_sqr() const
{
T result(0.0);
for (N i = 0; i < n; ++i) {
for (Iterator it = row_begin(i); it; ++it) {
result += (it.value()) * (it.value());
}
}
return result;
}
void write_matlab(std::ostream &output,
unsigned int rows,
unsigned int columns,
const char *variable_name)
{
output << variable_name << "=sparse([";
for (N i = 0; i < n; ++i) {
if (matrix[i]) {
const std::vector<N> &index = matrix[i]->index;
for (N j = 0; j < (N)index.size(); ++j) {
output << i + 1 << " ";
}
}
}
output << "],...\n [";
for (N i = 0; i < n; ++i) {
if (matrix[i]) {
const std::vector<N> &index = matrix[i]->index;
for (N j = 0; j < (N)index.size(); ++j) {
output << index[j] + (offsets.empty() ? 0 : offsets[i]) + 1 << " ";
}
}
}
output << "],...\n [";
for (N i = 0; i < n; ++i) {
if (matrix[i]) {
const std::vector<T> &value = matrix[i]->value;
for (N j = 0; j < value.size(); ++j) {
output << value[j] << " ";
}
}
}
output << "], " << rows << ", " << columns << ");" << std::endl;
};
void export_matlab(std::string filename, std::string name)
{
// Export this matrix
std::ofstream file;
file.open(filename.c_str());
write_matlab(file, n, getColumnSize(), name.c_str());
file.close();
}
void print_readable(std::string name, bool printNonZero = true)
{
std::cout << name << " \n";
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (printNonZero) {
if ((*this)(i, j) == 0) {
std::cout << " .";
continue;
}
}
else {
if ((*this)(i, j) == 0) {
continue;
}
}
if ((*this)(i, j) >= 0)
std::cout << " ";
std::cout << " " << (*this)(i, j);
}
std::cout << " \n";
}
}
///
N n;
N expected_none_zeros;
std::vector<RowEntry *> matrix;
std::vector<int> offsets;
};
template<class N, class T>
static inline RCMatrix<N, T> operator*(const std::vector<T> &diagonal, const RCMatrix<N, T> &A)
{
RCMatrix<N, T> result(A);
parallel_for(result.n)
{
N row(parallel_index);
for (auto it = result.dynamic_row_begin(row); it; ++it) {
it.setValue(it.value() * diagonal[row]);
}
}
parallel_end return std::move(result);
}
template<class N, class T> struct RCFixedMatrix {
std::vector<N> rowstart;
std::vector<N> index;
std::vector<T> value;
N n;
N max_rowlength;
//
RCFixedMatrix() : n(0), max_rowlength(0)
{
}
RCFixedMatrix(const RCMatrix<N, T> &matrix)
{
n = matrix.n;
rowstart.resize(n + 1);
rowstart[0] = 0;
max_rowlength = 0;
for (N i = 0; i < n; i++) {
if (!matrix.empty(i)) {
rowstart[i + 1] = rowstart[i] + matrix.row_nonzero_size(i);
max_rowlength = std::max(max_rowlength, rowstart[i + 1] - rowstart[i]);
}
else {
rowstart[i + 1] = rowstart[i];
}
}
value.resize(rowstart[n]);
index.resize(rowstart[n]);
N j = 0;
for (N i = 0; i < n; i++) {
for (typename RCMatrix<N, T>::Iterator it = matrix.row_begin(i); it; ++it) {
value[j] = it.value();
index[j] = it.index();
++j;
}
}
}
class Iterator : std::iterator<std::input_iterator_tag, T> {
public:
Iterator(N start, N end, const std::vector<N> &index, const std::vector<T> &value)
: index_array(index), value_array(value), k(start), start(start), end(end)
{
}
operator bool() const
{
return k < end;
}
Iterator &operator++()
{
++k;
return *this;
}
T value() const
{
return value_array[k];
}
N index() const
{
return index_array[k];
}
N size() const
{
return end - start;
}
private:
const std::vector<N> &index_array;
const std::vector<T> &value_array;
N k, start, end;
};
Iterator row_begin(N n) const
{
return Iterator(rowstart[n], rowstart[n + 1], index, value);
}
std::vector<T> operator*(const std::vector<T> &rhs) const
{
std::vector<T> result(n, 0.0);
multiply(rhs, result);
return result;
}
void multiply(const std::vector<T> &rhs, std::vector<T> &result) const
{
result.resize(n);
parallel_for(n)
{
N i = parallel_index;
T new_value = 0.0;
for (Iterator it = row_begin(i); it; ++it) {
N j_index = it.index();
assert(j_index < rhs.size());
new_value += rhs[j_index] * it.value();
}
result[i] = new_value;
}
parallel_end
}
RCMatrix<N, T> operator*(const RCFixedMatrix &m) const
{
RCMatrix<N, T> result(n, max_rowlength);
// Run in parallel
parallel_for(result.n)
{
N i = parallel_index;
for (Iterator it_A = row_begin(i); it_A; ++it_A) {
N j = it_A.index();
assert(j < m.n);
T a = it_A.value();
if (std::abs(a) > VECTOR_EPSILON) {
for (Iterator it_B = m.row_begin(j); it_B; ++it_B) {
result.add_to_element(i, it_B.index(), it_B.value() * a);
}
}
}
}
parallel_end return result;
}
RCMatrix<N, T> toRCMatrix() const
{
RCMatrix<N, T> result(n, 0);
parallel_for(n)
{
N i = parallel_index;
N size = rowstart[i + 1] - rowstart[i];
result.matrix[i] = new typename RCMatrix<N, T>::RowEntry;
result.matrix[i]->index.resize(size);
result.matrix[i]->value.resize(size);
for (N j = 0; j < size; j++) {
result.matrix[i]->index[j] = index[rowstart[i] + j];
result.matrix[i]->value[j] = value[rowstart[i] + j];
}
}
parallel_end return result;
}
};
typedef RCMatrix<int, Real> Matrix;
typedef RCFixedMatrix<int, Real> FixedMatrix;
}
#undef parallel_for
#undef parallel_end
#undef parallel_block
#undef do_parallel
#undef do_end
#undef block_end
#endif