Lower triangular of matrix in eigen - c++

How to use eigen library to compute lower triangular of input matrix without changing columns order?
for example for matrix:
A=[1 2 3;4 5 6 ;7 8 9]
I want the result to be:
1 0 0
4 0 0
7 0 0

Your text and your example don't match. I'll go through the three possible ways I understood your question. First, we'll set up the matrix:
Matrix3d mat;
mat << 1, 2, 3, 4, 5, 6, 7, 8, 9;
If you wanted the actual lower triangular matrix, you would use:
std::cout << Matrix3d(mat.triangularView<Lower>()) << "\n\n";
or similar. The result is:
1 0 0
4 5 0
7 8 9
Note the 5,8,9 which are missing from your example. If you just wanted the left-most column, you would use:
std::cout << mat.col(0) << "\n\n";
which gives
1
4
7
If (as the second part of your example shows) you want mat * [1, 0, 0] then you could either do the matrix multiplication (not recommended) or just construct the result:
Matrix3d z = Matrix3d::Zero();
z.col(0) = mat.col(0);
std::cout << z << "\n\n";
which gives the same result as your example:
1 0 0
4 0 0
7 0 0

Related

How to roll the rows of a Eigen:Matrix?

I want to reindex a Eigen:Matrix by rolling N∈ℤ rows like this (here N=+1):
1 4 7 -> 3 6 9
2 5 8 1 4 7
3 6 9 2 5 8
Is there a simple way, or do I have to create a new matrix and copy over the data?
I suggest setting up a new matrix and copying the data. Eigen's block operations allow doing this in an efficient way. Here is how a shift by n rows can be done for the example above.
MatrixXi A(3,3);
A << 1, 2, 3, 4, 5, 6, 7, 8, 9;
A.transposeInPlace();
int n = 1; // number of shifts
n = n % A.rows();
MatrixXi B(A.rows(), A.cols());
B.bottomRows(A.rows() - n) = A.topRows(A.rows() - n);
B.topRows(n) = A.bottomRows(n);
std::cout << "B = " << B << std::endl;
If you are interested in a matlab-like syntax you can also use
MatrixXd A;
//... fill A
VectorXi indices = {{2,0,1}};
A(indices, Eigen::all);
I don't know, whether this internally makes a copy.
Note: This does not work for Sparse matrices, see Subset columns of sparse eigen matrix

How can one find all the adjacent vertices, given a table of vertices with a specific rectangle format?

If I have a table of vertexes represented by:
a b c d
e f g h
i j k l
m n o p
How can I get the adjacencies of a node as indexes, if the indexes for this table is as follows:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
For example, node "a" should result: 1, 4, 5. node "f" results in 0, 1, 2, 4, 6, 8, 9, 10.
How can this be expanded to a table of any size? This is a 4x4, what about a 10x10? 3x4?
Can this be found with code? c++ preferred.
So far I tried: Since it's a 4x4 I tried subtracting 4 and adding 4 from the index of the node in question. However, this does not work for every node, especially the edge and corner nodes.
Here, every node is connected to 8-directional way. So we will try to get grid number of 8 adjacent cells.
// starting from upper left corner for a cell
int dr[8] = {-1, -1, -1, 0, 1, 1, 1, 0}; // 8 direction row
int dc[8] = {-1, 0, 1, 1, 1, 0, -1, -1}; // 8 direction column
int n = 20;
int m = 30;
int r = 1, c = 1; // position of 'f' is (1, 1)
for(int i = 0; i < 8; i++) {
int adjr = r + dr[i];
int adjc = c + dc[i];
if (adjr < 0 || adjr >= n || adjc < 0 || adjc >= m) continue; // check for invalid cells
cout << adjr << " " << adjc << endl; // {row, column} which is connected
}
Outputs:
0 0
0 1
0 2
1 2
2 2
2 1
2 0
1 0
These cells are connected to (1,1).

Is it safe to traverse a container during std::remove_if execution?

Suppose I want to remove the unique elements from an std::vector (not get rid of the duplicates, but retain only the elements that occur at least 2 times) and I want to achieve that in a pretty inefficient way - by calling std::count while std::remove_ifing. Consider the following code:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 6, 3, 6, 2, 7, 4, 4, 5, 6};
auto to_remove = std::remove_if(vec.begin(), vec.end(), [&vec](int n) {
return std::count(vec.begin(), vec.end(), n) == 1;
});
vec.erase(to_remove, vec.end());
for (int i : vec) std::cout << i << ' ';
}
From reference on std::remove_if we know that the elements beginning from to_remove have unspecified values, but I wonder how unspecified they can really be.
To explain my concern a little further - we can see that the elements that should be removed are 1, 3, 5 and 7 - the only unique values. std::remove_if will move the 1 to the end but there is no guarantee that there will be a value 1 at the end after said operation. Can this be (due to that value being unspecified) that it will turn into 3 and make the std::count call return a count of (for example) 2 for the later encountered value 3?
Essentially my question is - is this guaranteed to work, and by work I mean to inefficiently erase unique elements from an std::vector?
I am interested in both language-lawyer answer (which could be "the standard says that this situation is possible, you should avoid it") and in-practice answer (which could be "the standard says that this situation is possible, but realistically there is no way of this value ending up as a completely differeny one, for example 3").
After the predicate returns true the first time, there will be one unspecified value in the range. That means any subsequent calls of the predicate will count an unspecified value. The count is therefore potentially incorrect, and you may either leave values unaffected that you intend to be discarded, or discard values that should be retained.
You could modify the predicate so it keeps a count of how many times it has returned true, and reduce the range accordingly. For example;
std::size_t count = 0;
auto to_remove = std::remove_if(vec.begin(), vec.end(), [&vec, &count](int n)
{
bool once = (std::count(vec.begin(), vec.end() - count, n) == 1);
if (once) ++count;
return once;
});
Subtracting an integral value from a vector's end iterator is safe, but that isn't necessarily true for other containers.
You misunderstood how std::remove_if works. The to-be-removed values are not necessarily shifted to the end. See:
Removing is done by shifting (by means of move assignment) the elements in the range in such a way that the elements that are not to be removed appear in the beginning of the range. cppreference
This is the only guarantee for the state of the range. According to my knowledge, it's not forbidden to shift all values around and it would still satisfy the complexity. So it might be possible that some compilers shift the unwanted values to the end but that would be just extra unnecessary work.
An example of possible implementation of removing odd numbers from 1 2 3 4 8 5:
v - read position
1 2 3 4 8 5 - X will denotes shifted from value = unspecified
^ - write position
v
1 2 3 4 8 5 1 is odd, ++read
^
v
2 X 3 4 8 5 2 is even, *write=move(*read), ++both
^
v
2 X 3 4 8 5 3 is odd, ++read
^
v
2 4 3 X 8 5 4 is even, *write=move(*read), ++both
^
v
2 4 8 X X 5 8 is even, *write=move(*read), ++both
^
2 4 8 X X 5 5 is odd, ++read
^ - this points to the new end.
So, in general, you cannot rely on count returning any meaningful values. Since in the case that move==copy (as is for ints) the resulting array is 2 4 8|4 8 5. Which has incorrect count both for the odd and even numbers. In case of std::unique_ptr the X==nullptr and thus the count for nullptr and removed values might be wrong. Other remaining values should not be left in the end part of the array as there were no copies done.
Note that the values are not unspecified as in you cannot know them. They are exactly the results of move assignments which might leave the value in unspecified state. If it specified the state of the moved-from variables ( asstd::unique_ptr does) then they would be known. E.g. if move==swap then the range will be permuted only.
I added some outputs:
#include <algorithm>
#include <iostream>
#include <vector>
#include <mutex>
int main() {
std::vector<int> vec = {1, 2, 6, 3, 6, 2, 7, 4, 4, 5, 6};
auto to_remove = std::remove_if(vec.begin(), vec.end(), [&vec](int n) {
std::cout << "number " << n << ": ";
for (auto i : vec) std::cout << i << ' ';
auto c = std::count(vec.begin(), vec.end(), n);
std::cout << ", count: " << c << std::endl;
return c == 1;
});
vec.erase(to_remove, vec.end());
for (int i : vec) std::cout << i << ' ';
}
and got
number 1: 1 2 6 3 6 2 7 4 4 5 6 , count: 1
number 2: 1 2 6 3 6 2 7 4 4 5 6 , count: 2
number 6: 2 2 6 3 6 2 7 4 4 5 6 , count: 3
number 3: 2 6 6 3 6 2 7 4 4 5 6 , count: 1
number 6: 2 6 6 3 6 2 7 4 4 5 6 , count: 4
number 2: 2 6 6 3 6 2 7 4 4 5 6 , count: 2
number 7: 2 6 6 2 6 2 7 4 4 5 6 , count: 1
number 4: 2 6 6 2 6 2 7 4 4 5 6 , count: 2
number 4: 2 6 6 2 4 2 7 4 4 5 6 , count: 3
number 5: 2 6 6 2 4 4 7 4 4 5 6 , count: 1
number 6: 2 6 6 2 4 4 7 4 4 5 6 , count: 3
2 6 6 2 4 4 6
As you can see the counts can be wrong. I'm not able to create an example for your special case but as a rule you have to worry about wrong results.
First the number 4 is counted twice and in the next step the number 4 is counted thrice. The counts are wrong and you can't rely on them.

How can I get a discontiguous "block" of data from an eigen matrix?

Suppose I wanted to apply some generic operation a matrix consisting of some subset of its values that are not necessarily contiguous. How can I do this?
If the values were contiguous I would simply use the Eigen::block operation, but what if they are not?
One application might be that I have an eigen matrix of positive integers:
Eigen::Matrix<int, 4, 1> mat;
mat << 4, 1, 2, 8;
And I wanted to return the 0th, 2nd and 3rd values. If they were contiguous (0th, 1st and 2nd) I could simply use the block operation on this matrix, but what do I do in this case?
How about rearranging the elements to make them contiguous?
1 0 0 0 4 4
0 0 1 0 x 1 = 2
0 0 0 1 2 8
0 0 0 0 8 0

SparseMatrix in Eigen

If I set the value of a SparseMatrix entry in Eigen as follows:
sparse_matrix->coeffref(10, 10) = 0;
Would this actually shrink the storage required by the matrix or would it try and store a 0 and use up 4 bytes there (assuming integer type)?
if the answer is the latter, how can I set columns to 0, so that it does not use any extra space?
Also, what about something like this:
typedef Eigen::Triplet<double> TripletType;
std::vector<TripletType> t;
for (int i = 0; i < some_value; ++i) {
for (int j = 0; j < some_value; ++j) {
t->push_back(TripletType(i, j, 0);
}
}
sparse_matrix->setFromTriplets(t);
Would this result in explicit zeros in the sparse matrix?
After insertion with coeffRef you can prune the sparse matrix like:
Eigen::SparseMatrix<double, Eigen::ColMajor> A(5,5);
// fill A
A.insert(0,0)=9.;
A.insert(1,0)=3.0/2.0;
A.insert(0,1)=3.0/2.0;
A.insert(2,0)=6.0;
A.insert(0,2)=6.0;
A.insert(3,0)=3.0/4.0;
A.insert(0,3)=3.0/4.0;
A.insert(4,0)=3.0;
A.insert(0,4)=3.0;
A.insert(1,1)=1.0/2.0;
A.insert(2,2)=12.0;
A.insert(3,3)=5.0/8.0;
A.insert(4,4)=16.0;
std::cout << A << std::endl;
std::cout << A.data().size() << std::endl;
A.coeffRef(3,0) = 0;
A.prune(0,0); // Suppresses all nonzeros which are much smaller than reference under the tolerence epsilon
std::cout << A << std::endl;
std::cout << A.data().size() << std::endl;`
Output:
Nonzero entries:
(9,0) (1.5,1) (6,2) (0.75,3) (3,4) (_,_) (_,_) (_,_) (1.5,0) (0.5,1) (6,0) (12,2
) (0.75,0) (0.625,3) (3,0) (16,4)
Outer pointers:
0 8 10 12 14 $
Inner non zeros:
5 2 2 2 2 $
9 1.5 6 0.75 3
1.5 0.5 0 0 0
6 0 12 0 0
0.75 0 0 0.625 0
3 0 0 0 16
16
Nonzero entries:
(9,0) (1.5,1) (6,2) (3,4) (1.5,0) (0.5,1) (6,0) (12,2) (0.75,0) (0.625,3) (3,0)
(16,4)
Outer pointers:
0 4 6 8 10 $
9 1.5 6 0.75 3
1.5 0.5 0 0 0
6 0 12 0 0
0 0 0 0.625 0
3 0 0 0 16
12
You can see that the size has changed from 16 to 12, as also the three (_,_) are removed.
I didn't check with sizeof() if memory storage that is needed is really less.