I have two sparse matrices in Eigen, and I would like to join them vertically into one. As an example the target of the code would be:
SparseMatrix<double> matrix1;
matrix1.resize(10, 10);
SparseMatrix<double> matrix2;
matrix2.resize(5, 10);
SparseMatrix<double> MATRIX_JOIN;
MATRIX_JOIN.resize(15, 10);
MATRIX_JOIN << matrix1, matrix2;
I found some solutions on a forum however, I wasn't able to implement it.
What's the proper way to join the matrices vertically?
Edit
My implementation:
SparseMatrix<double> L;
SparseMatrix<double> C;
// ... (Operations with the matrices)
SparseMatrix<double> EMATRIX;
EMATRIX.resize(L.rows() + C.rows(), L.cols());
EMATRIX.middleRows(0, L.rows()) = L;
EMATRIX.middleRows(L.rows(), C.rows()) = C;
I get an error of types, acording to the compiler the right hand side is an Eigen::Block and the left side is Eigen::SparseMatrix
As far as I know, there is currently no built-in solution. You can be way more efficient than your solution by using the internal insertBack function:
SparseMatrix<double> M(L.rows() + C.rows(), L.cols());
M.reserve(L.nonZeros() + C.nonZeros());
for(Index c=0; c<L.cols(); ++c)
{
M.startVec(c); // Important: Must be called once for each column before inserting!
for(SparseMatrix<double>::InnerIterator itL(L, c); itL; ++itL)
M.insertBack(itL.row(), c) = itL.value();
for(SparseMatrix<double>::InnerIterator itC(C, c); itC; ++itC)
M.insertBack(itC.row()+L.rows(), c) = itC.value();
}
M.finalize();
Based on #Javier's answer.
Fixed the number of columns in the output matrix (just cols instead of cols+cols)
Fixed the lower matrice's triplet indices (upper.rows() + it.row() instead of just it.row())
using sparse_matrix_type = Eigen::SparseMatrix<T>;
using triplet_type = Eigen::Triplet<T, size_t>;
static sparse_matrix_type sparse_vstack(sparse_matrix_type const& upper, sparse_matrix_type const& lower) {
assert(upper.cols() == lower.cols() && "vstack with mismatching number of columns");
std::vector<triplet_type> triplets;
triplets.reserve(upper.nonZeros() + lower.nonZeros());
for (int k = 0; k < upper.outerSize(); ++k) {
for (sparse_matrix_type::InnerIterator it(upper, k); it; ++it) {
triplets.emplace_back(it.row(), it.col(), it.value());
}
}
for (int k = 0; k < lower.outerSize(); ++k) {
for (sparse_matrix_type::InnerIterator it(lower, k); it; ++it) {
triplets.emplace_back(upper.rows() + it.row(), it.col(), it.value());
}
}
sparse_matrix_type result(lower.rows() + upper.rows(), upper.cols());
result.setFromTriplets(triplets.begin(), triplets.end());
return result;
}
Unfortunately I coulnd't get #chtz's example to work with Eigen 3.3.4 due to a static assertion error THIS_SPARSE_BLOCK_SUBEXPRESSION_IS_READ_ONLY. It seems to be explicitly forbidden by Eigen (see https://eigen.tuxfamily.org/dox/SparseBlock_8h_source.html).
I ended up doing the following:
MATRIX_JOIN.resize(matrix1.rows() + matrix2.rows(), matrix1.cols() + matrix2.cols());
MATRIX_JOIN.setZero();
// Fill MATRIX_JOIN with triples from the other matrices
std::vector<Triplet<double> > tripletList;
for (int k = 0; k < matrix1.outerSize(); ++k)
{
for (SparseMatrix<double>::InnerIterator it(matrix1, k); it; ++it)
{
tripletList.push_back(Triplet<double>(it.row(), it.col(), it.value()));
}
}
for (int k = 0; k < matrix2.outerSize(); ++k)
{
for (SparseMatrix<double>::InnerIterator it(matrix2, k); it; ++it)
{
tripletList.push_back(Triplet<double>(it.row(), it.col(), it.value()));
}
}
FINALMATRIX.setFromTriplets(tripletList.begin(), tripletList.end());
There can be a speedup by calling tripleList.reserve(X) with X being the expected amount of triplets to insert.
Related
I would like to know if there is a function or an optimized way to reshape sparse matrices in Eigen.
In the documentation there is no reshape method for such matrices, so I implemented a function myself, but I don't know if it is optimized (i need it to be as fast as possible). Here is my approach:
Eigen::SparseMatrix<double> reshape_sp(const Eigen::SparseMatrix<double>& x,
lint a, lint b) {
Eigen::SparseMatrix<double> y(a, b);
for (int k=0; k<x.outerSize(); ++k) {
for (Eigen::SparseMatrix<double>::InnerIterator it(x,k); it; ++it) {
int pos = it.col()*x.rows()+it.row();
int col = int(pos/a);
int row = pos%a;
y.insert(row, col) = it.value();
}
}
y.makeCompressed();
return y;
}
For performance, it is absolutely crucial that you call reserve on your matrix. I've tested with a 100,000 x 100,000 matrix population 1%. Your version (after fixing the 32 bit overflow in pos computation), took 3 minutes. This fixed version a few seconds:
Eigen::SparseMatrix<double>
reshape(const Eigen::SparseMatrix<double>& orig,
int rows, int cols)
{
Eigen::SparseMatrix<double> rtrn(rows, cols);
rtrn.reserve(orig.nonZeros());
using InnerIterator = Eigen::SparseMatrix<double>::InnerIterator;
for(int k = 0; k < orig.outerSize(); ++k) {
for(InnerIterator it(orig, k); it; ++it) {
std::int64_t pos = std::int64_t(it.col()) * orig.rows() + it.row();
int col = int(pos / rows);
int row = int(pos % rows);
rtrn.insert(row, col) = it.value();
}
}
rtrn.makeCompressed();
return rtrn;
}
An alternative is to work with triplets again. This is a bit slower but less likely to explode in your face the same way insert does. This is particularly helpful for more complex operations like transposing where you cannot guarantee that the insert appends at the end.
Eigen::SparseMatrix<double>
reshape(const Eigen::SparseMatrix<double>& orig,
int rows, int cols)
{
using InnerIterator = Eigen::SparseMatrix<double>::InnerIterator;
using Triplet = Eigen::Triplet<double>;
std::vector<Triplet> triplets;
triplets.reserve(std::size_t(orig.nonZeros()));
for(int k = 0; k < orig.outerSize(); ++k) {
for(InnerIterator it(orig, k); it; ++it) {
std::int64_t pos = std::int64_t(it.col()) * orig.rows() + it.row();
int col = int(pos / rows);
int row = int(pos % rows);
triplets.emplace_back(row, col, it.value());
}
}
Eigen::SparseMatrix<double> rtrn(rows, cols);
rtrn.setFromTriplets(triplets.begin(), triplets.end());
return rtrn;
}
Things I tested that did not work:
Using FXDiv to replace the division with a cheaper operation
Computing maximum distance from one index to the next within a single column to skip dividing if both values are in the same output column (may still be worth it for sparse matrices with suitable inner structure)
Parallelizing the loop with OpenMP, using a final std::sort(std::execution::par, ...) for the triplets.
I need to program all possible sets of numbers from 1 to N for an arbitrary number m of integers without permutation.
Since I don't know how to explain it better here are some examples:
for m = 2
vector<vector<int>> box;
int N = 5;
for(int i = 1; i <= N; i++) {
for(int j = N; j >= i; j--) {
vector<int> dummy;
dummy.push_back(i);
dummy.push_back(j);
box.push_back(dummy);
}
}
for m = 3
vector<vector<int>> box;
int N = 5;
for(int i = 1; i <= N; i++) {
for(int j = N; j >= i; j--) {
for(int k = N; k >= j; k--) {
vector<int> dummy;
dummy.push_back(i);
dummy.push_back(j);
dummy.push_back(k);
box.push_back(dummy);
}
}
}
This works perfectly fine and the result is what I need. But like already mentioned, m can be arbitrary and I can't be bothered to implement this for m = 37 or what ever. N and m are known values but change while the program is running. There must be a better way to implement this than for the m = 37 case to implement a row of 37-for-loops. Can someone help me? I'm kind a clueless :\
edit: to explain better what I'm looking for here are some more examples.
Let's say N = 5 and m = 4, than 1223 is a feasible solution for me, 124 is not since it is to short. Let's say I already found 1223 as a solution, than I don't need 2123, 2213 or any other permutation of this number.
edit2: Or if you prefer a more visual (mathematical?) problem formulation here you go.
Consider m the dimension. With m been 2 you are left with a N size Matrix. I am looking for the upper (or lower) triangle of this Matrix including the diagonal. Let's move to m = 3, the Matrix becomes a 3 dimensional cube (or Tensor if you so wish), now I'm looking for the upper (or lower) tetrahedron including the diagonal-plain. For higher dimensions than 3 I'm looking for the hyper-tetrahedron of the hyper-cube including the hyper-diagonal-plane.
http://howardhinnant.github.io/combinations.html
The following generic algorithms permit a client to visit every combination or permuation of a sequence of length N, r items at time.
Example usage:
std::vector<std::vector<int>> box;
std::vector<int> v(N);
std::iota(begin(v), end(v), 1);
for_each_combination(begin(v), begin(v) + M, end(v), [](auto b, auto e) {
box.emplace_back(b, e);
return false;
});
The above code just shows inserting each combination into box as an example, but you probably don't want to actually do that: assuming that box is simply an intermediary and that your actual work then uses it somewhere else, you can avoid an intermediary and simply do whatever work you need directly in the body of the functor.
Here's a complete, working example using code from the provided link.
Since what you want is combinations with repetition rather than just combinations. Here's an example of implementing this on top of for_each_combination():
template<typename Func>
void for_each_combination_with_repetition(int categories, int slots, Func func) {
std::vector<int> v(slots + categories - 1);
std::iota(begin(v), end(v), 1);
std::vector<int> indices;
for_each_combination(begin(v), begin(v) + slots, end(v), [&](auto b, auto e) {
indices.clear();
int last = 0;
int current_element = 0;
for(;b != e; ++last) {
if (*b == last+1) {
indices.push_back(current_element);
++b;
} else {
++current_element;
}
}
func(begin(indices), end(indices));
return false;
});
}
The wikipedia article on combinations shows a good illustration of what this is doing: it's getting all the combinations (without repetition) of numbers [0, N + M - 1) and then looking for the 'gaps' in the results. The gaps represent transitions from repetitions of one element to repetitions of the next.
The functor you pass to this algorithm is given a range that contains indices into a collection containing the elements you're combining. For example if you want to get all sets of three elements from the set of {x,y}, the results are you want are {{x,x,x}, {x,x,y}, {x,y,y}, {y,y,y}}, and this algorithm represents this by returning ranges of indices into the (ordered) set {x,y}: {{0,0,0}, {0,0,1}, {0,1,1}, {1,1,1}}.
So normally to use this you have a vector or something containing your elements and use the ranges produced by this algorithm as indices into that container. However in your case, since the elements are just the numbers from 1 to N you can use the indices directly by adding one to each index:
for_each_combination_with_repetition(N, M, [&](auto b, auto e) {
for(; b != e; ++b) {
int index = *b;
std::cout << index + 1 << " ";
}
std::cout << '\n';
});
Complete example
An alternative implementation can return vectors that represent counts of each category. E.g. the earlier {{x,x,x}, {x,x,y}, {x,y,y}, {y,y,y}} results could be represented by: {{3,0} {2,1},{1,2}, {0,3}}. Modifying the implementation to produce this representation instead looks like this:
template<typename Func>
void for_each_combination_with_repetition(int categories, int slots, Func func) {
std::vector<int> v(slots + categories - 1);
std::iota(begin(v), end(v), 1);
std::vector<int> repetitions(categories);
for_each_combination(begin(v), begin(v) + slots, end(v), [&](auto b, auto e) {
std::fill(begin(repetitions), end(repetitions), 0);
int last = 0;
int current_element = 0;
for(;b != e; ++last) {
if (*b == last+1) {
++repetitions[current_element];
++b;
} else {
++current_element;
}
}
func(begin(repetitions), end(repetitions));
return false;
});
}
You can use recursion to find all subsets. This can probably be improved stylistically, but here is a quick take at the problem:
std::vector<std::set<int>> subsets(std::vector<int> x)
{
if (x.size() == 0)
return { std::set<int>() };
else
{
int last = x.back();
x.pop_back();
auto sets = subsets(x);
size_t n = sets.size();
for (size_t i = 0; i < n; i++)
{
std::set<int> s = sets[i];
s.insert(last);
sets.push_back(std::move(s));
}
return sets;
}
}
This doubles the number of answers at each recursion step : the number of subsets is 2^n, as expected.
You can substitute std::set for std::vector if you wish.
I have a 3D point vector, represented by class Point3D,
std::vector<Point3D> points;
I also have a size_t vector containing indices of the points vector,
std::vector<size_t> indices_true;
Now I want to build the inverse of indices_true, i.e. I want to build another index vector indices_false that contains all indices which are missing in indices_true. How can this be done in a faster way than the following:
for (size_t i = 0; i < points.size(); i++)
{
// TODO: The performance of the following is awful
if (std::find(indices_true.begin(), indices_true.end(), i) == indices_true.end())
indices_false.push_back(i);
}
Needs extra memory, but yields a linear algorithm:
Here is an attempt (neither compiled, nor tested):
indices_false.reserve(points.size() - indices_true.size());
std::vector<char> isTrue(points.size(), false); // avoided std::vector<bool> intentionally
for (const size_t i : indices_true)
{
isTrue[i] = true;
}
for (size_t i = 0; i < points.size(); ++i)
{
if (!isTrue[i])
indices_false.push_back(i);
}
Sort your indices_true vector first and use std::binary_search. To keep the orders within vector using std::stable_sort.
std::stable_sort(indices_true.begin(), indices_true.end());
for (size_t i = 0; i < points.size(); i++)
{
if (std::binary_search(indices_true.begin(), indices_true.end(), i))
indices_false.push_back(i);
}
Sort indices_true and gradually increase an index k within this sorted vector. Increase it when necessary. This yields (beside the initial sorting) a linear algorithm.
Here is an attempt (neither compiled, nor tested):
std::sort(begin(indices_true), end(indices_true));
indices_false.reserve(points.size() - indices_true.size());
size_t k = 0;
for (size_t i = 0; i < points.size(); ++i)
{
if (k < indices_true.size() && i > indices_true[k])
++k;
assert(k >= indices_true.size() || i <= indices_true[k]);
if (k >= indices_true.size() || i != indices_true[k])
indices_false.push_back(i);
}
}
I have a complex vector (VSII_Complex containing Eigen values) and a complex matrix (CUII_Complex containing Eigen vectors). Each element of VSII_Complex is corresponding to a column of CUII_Complex. My problem is that I want to sort the Eigen values inside VSII_Complex
based on their real part (NOT imaginary part) and I will have to sort the columns of CUII_Complex according to the sorted VSII_Complex. The following code is developed by my friend but I feel like something is wrong with this code but I cannot figure it out. I wonder if anybody can tell what is wrong if any.
EIG eigA=EIG(m_IIStiffnessAct,m_IIMassAct,true);
ComplexColumnVector VSII_Complex=eigA.eigenvalues();
ComplexMatrix CUII_Complex=eigA.eigenvectors();
///// make eigenvalues in decreasing order, so do eigenvectors
for (long ii = 0; ii < VSII_Complex.rows(); ii++)
{
for (long jj = ii+1; jj < VSII_Complex.rows(); jj++)
{
if (VSII_Complex(ii).real() < VSII_Complex(jj).real())
{
Complex temp = VSII_Complex(ii);
VSII_Complex(ii) = VSII_Complex(jj);
VSII_Complex(jj) = temp;
for (long kk = 0; kk < CUII_Complex.rows(); kk++)
{
Complex tempVec = CUII_Complex(kk,ii);
CUII_Complex(kk,ii) = CUII_Complex(kk,jj);
CUII_Complex(kk,jj) = tempVec;
}
}
}
}
Just use the build-in sort that returns the position that the element was in previously.
//couldn't find this in the docs, I'm overlooking something probably:
void swapColumns (ComplexMatrix &mat, octave_idx_type colA, octave_idx_type colB)
{
if(colA == colB) return;
ComplexColumnVector temp = mat.column(colA);
mat.insert(mat.column(colB),0,colA);
mat.insert(temp,0,colB);
}
bool isRealGreater(const Complex& a, const Complex& b)
{
return a.real() > b.real();
}
//presumably in another function
//int func() {
EIG eigA=EIG(m_IIStiffnessAct,m_IIMassAct,true);
ComplexColumnVector VSII_Complex=eigA.eigenvalues();
ComplexMatrix CUII_Complex=eigA.eigenvectors();
///// make eigenvalues in decreasing order, so do eigenvectors
//create indices from 1-len(VSII_Complex)
Array<octave_idx_type> sort_order(VSII_Complex.length(),0);
for(int i =0 ; i< sort_order.length(); i++)
{sort_order.elem(i)= i;}
//create sorting object and sort VSII_Complex in descending order of the real component
octave_sort<Complex> sort_obj(&isRealGreater);
sort_obj.sort(VSII_Complex.jit_slice_data(), sort_order.jit_slice_data(), VSII_Complex.length());
//swap the columns of CUII_Complex in the same way VSII_Complex got sorted
for(octave_idx_type i=0; i<sort_order.length(); i++)
{
if(sort_order.elem(i) > i)
{
swapColumns(CUII_Complex,i,sort_order.elem(i));
}
}
//}
Haven't actually tested this, because I was too lazy to install octave, I just read the docs.
I solved the problem with the following code, I developed this code based on the algorithm in the following webpage. But the answer of PeterT looks better to me.
http://www.learncpp.com/cpp-tutorial/64-sorting-an-array-using-selection-sort/
///// make eigenvalues in decreasing order, so do eigenvectors
ComplexColumnVector ComplexColumnVector_toBesSorted=VSII_Complex;
ComplexMatrix ComplexMatrix_toBeSorted=CUII_Complex;
for (long idx_start = 0; idx_start < ComplexColumnVector_toBesSorted.rows(); idx_start++)
{
long idx_smallest=idx_start;
for (long idx_current = idx_start+1; idx_current < ComplexColumnVector_toBesSorted.rows(); idx_current++)
{
if (ComplexColumnVector_toBesSorted(idx_current).real() < ComplexColumnVector_toBesSorted(idx_smallest).real())
idx_smallest=idx_current;
}
Complex Complex_temp=ComplexColumnVector_toBesSorted(idx_start);
ComplexColumnVector_toBesSorted(idx_start)=ComplexColumnVector_toBesSorted(idx_smallest);
ComplexColumnVector_toBesSorted(idx_smallest)=Complex_temp;
for (long kk = 0; kk < ComplexMatrix_toBeSorted.rows(); kk++)
{
Complex Complex_temp_2 = ComplexMatrix_toBeSorted(kk,idx_start);
ComplexMatrix_toBeSorted(kk,idx_start) = ComplexMatrix_toBeSorted(kk,idx_smallest);
ComplexMatrix_toBeSorted(kk,idx_smallest) = Complex_temp_2;
}
}
I have a datastructure containing a vector of vectors which each consist of about ~16000000 double values.
I now want to median-combine these vectors, meaning, of each original vectors I take the values at place i, calculate the median of these and then store them in the resulting vector at place i.
I already have the straight-forward solution, but it is incredible slow:
vector< vector<double> > vectors; //vectors contains the datavectors
vector<double> tmp;
vector<double> result;
vector<double> tmpmedian;
double pixels = 0.0;
double matrixcount = vectors.size();
tmp = vectors.at(0);
pixels = tmp.size();
for (int i = 0; i < pixels; i++) {
for (int j = 0; j < matrixcount; j++) {
tmp = vectors.at(j);
tmpmedian.push_back(tmp.at(i));
}
result.push_back(medianOfVector(tmpmedian));
tmpmedian.clear();
}
return result;
And medianOfVector looks like this:
double result = 0;
if ((vec.size() % 2) != 0) {
vector<double>::iterator i = vec.begin();
vector<double>::size_type m = (vec.size() / 2);
nth_element(i, i + m, vec.end());
result = vec.at(m);
} else {
vector<double>::iterator i = vec.begin();
vector<double>::size_type m = (vec.size() / 2) - 1;
nth_element(i, i + m, vec.end());
result = (vec.at(m) + vec.at(m + 1)) / 2;
}
return result;
I there an algorithm or a way to do this faster, it takes nearly an eternity to do it.
Edit: Thank you for your replies, in case anyone is interested here is the fixed version, it now takes about 9sec to median combine three vectors with ~16000000 elements, mean combining takes around 3sec:
vector< vector<double> > vectors; //vectors contains the datavectors
vector<double> *tmp;
vector<double> result;
vector<double> tmpmedian;
tmp = &vectors.at(0);
int size = tmp->size();
int vectorsize = vectors.size();
for (int i = 0; i < size; i++) {
for (int j = 0; j < vectorsize; j++) {
tmp = &vectors.at(j);
tmpmedian.push_back(tmp->at(i));
}
result.push_back(medianOfVector(tmpmedian));
tmpmedian.clear();
}
return result;
And medianOfVector:
double result = 0;
if ((vec.size() % 2) != 0) {
vector<double>::iterator i = vec.begin();
vector<double>::size_type m = (vec.size() / 2);
nth_element(i, i + m, vec.end());
result = vec.at(m);
} else {
vector<double>::iterator i = vec.begin();
vector<double>::size_type m = (int) (((vec.size() - 1) / 2));
nth_element(i, i + m, vec.end());
double min = vec.at(m);
double max = *min_element(i + m + 1, vec.end());
result = (min + max) / 2;
}
return result;
}
A couple of points, both stemming from the fact that you've defined tmp as a vector instead of (for example) a reference.
vector<double> tmp;
tmp = vectors.at(0);
pixels = tmp.size();
Here you're copying the entirety of vectors[0] into tmp just to extract the size. You'll almost certainly gain some speed by avoiding the copy:
pixels = vectors.at(0).size();
Instead of copying the entire vector just to get its size, this just gets a reference to the first vector, and gets the size of that existing vector.
for (int i = 0; i < pixels; i++) {
for (int j = 0; j < matrixcount; j++) {
tmp = vectors.at(j);
tmpmedian.push_back(tmp.at(i));
}
Here you're again copying the entirety of vectors.at(j) into tmp. But (again) you don't really need a new copy of all the data--you're just retrieving a single item from that copy. You can retrieve the data you need directly from the original vector without copying the whole thing:
tmpmedian.push_back(vectors.at(j).at(i));
A possible next step would be to switch from using .at to operator[]:
tmpmedian.push_back(vectors[j][i]);
This is much more of a tradeoff though--it's not likely to gain nearly as much, and loses a bit of safety (range checking) in the process. To avoid losing safety, you could consider (for example) using range-based for loops instead of the counted for loops in your current code.
Along rather different lines, you could instead change from using a vector<vector<double>> to using a small wrapper around a vector to give 2D addressing into a single vector. Using this with a suitable column-wise iterator, you could avoid creating tmpmedian as basically a copy of a column of the original 2D matrix--instead, you'd pass a column-wise iterator to medianOfVector, and just iterate through a column of the original data in-place.