SparseMatrix in Eigen - c++

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.

Related

Eigen: Zero matrix with smaller matrix as the "diagonals"

Is it possible to create a 9x9 matrix where the "diagonal" is another matrix and the rest are zeroes, like this:
5 5 5 0 0 0 0 0 0
5 5 5 0 0 0 0 0 0
5 5 5 0 0 0 0 0 0
0 0 0 5 5 5 0 0 0
0 0 0 5 5 5 0 0 0
0 0 0 5 5 5 0 0 0
0 0 0 0 0 0 5 5 5
0 0 0 0 0 0 5 5 5
0 0 0 0 0 0 5 5 5
from a smaller 3x3 matrix repeated:
5 5 5
5 5 5
5 5 5
I am aware of the Replicate function but that repeats it everywhere in the matrix and doesn't maintain the zeroes. Is there a builtin way of achieving what I'm after?
One way of doing this is by using blocks where .block<3,3>(0,0) is a 3x3 block starting at 0,0. (Note: Your IDE might flag this line as an error but it will compile and run)
for (int x=0, x<3, x++){
zero_matrix.block<3,3>(x*3,x*3) = five_matrix;
}
You can use the (unsupported) KroneckerProduct module for that:
#include <unsupported/Eigen/KroneckerProduct>
int main()
{
Eigen::MatrixXd A = Eigen::kroneckerProduct(Eigen::Matrix3d::Identity(), Eigen::Matrix3d::Constant(5));
std::cout << A << '\n';
}

Reading single lines from file into vector

I have an input file of the following format:
# 1 2 3 4 5 6 7
0 0 0 1
1 0 0 1
2 0 0 1
3 0 0 1
5 0 0 1
6 0 0 1
# 0 0 2 2 4 4 5
0 0 0 1
0 1 0 1
0 2 0 1
0 3 0 1
# 9 10 11 12 13 14 15 16 17 18
0 0 0 1
0 0 1 1
0 0 2 1
0 0 3 1
Each line preceded by a # must be read into its own vector. The entries in between these vectors represent matrices that also must be read into their own matrix.
So from the input file above, what I want to end up having is the following:
knot1 = {1 2 3 4 5 6 7}
cp1= { {0,0,0,1} {1,0,0,1} {2,0,0,1} {3,0,0,1} {5,0,0,1} {6,0,0,1} }
knot2 = {0 0 2 2 4 4 5}
cp2= {{...} {...} {...} {...} }
knot3 = {9 10 11 12 13 14 15 16 17 18}
cp3= {{...} {...} {...} {...} }
Note, each vector is not necessarily the same size! Same goes for the matrices. Also, the number of #vectors and matrices can vary as well.
Here is what I have so far:
ifstream file;
file.open(filename.c_str());
if(file.fail()){
cout << "Cannot open " << filename << endl;
}
int curr_line = 0;
vector<int> knot_locations; //stores the locations of the #vectors
while(!file.eof()){ //loops over input file checking to see where the #vectors are
curr_line++;
string line;
getline(file,line);
if(line[0]=='#'){
knot_locations.push_back(curr_line);
}
}
for(int i=0; i < knot_locations.size(); i++){
file.seekg(std::ios::beg);
for(int i=0; i < knot_locations[i] - 1; ++i){ // this loop skips to the line that contains the #vectors.
file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
}
}
so now that I am at the line
containing the vector, how can I read
in JUST that SINGLE line into a vector?!
I'm not sure how to turn a string into
a vector of floats. Also, since I know all the
locations of the vectors, I can read everything
else between into the matrices. But again, same
problem. I am not sure how to go about actually
reading these into a numeric array/vector given a line (string)
file.close();
Probably better ways of doing this. Any ideas on how to go about this problem? The key is to be able to read all the vectors marked with a # into their own vector. There can be anywhere between 1-3 of these vectors. And in between each of these vectors is a matrix of unknown rows/columns that also need to be read into their own matrix. What I have above just locates the # marked vectors. Need help on how to read a string line into a numeric array OR a recommendation on a different way to go about this.
Thank you.

bit vector intersect in handling parquet file format

I am handling parquet file format. For example:
a group of data:
1 2 null 3 4 5 6 null 7 8 null null 9 10 11 12 13 14
I got a bit vector to indicate null element:
1 1 0 1 1 1 1 0 1 1 0 0 1 1 1 1 1 1
and only store the non-null element:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
I want to evaluate a predicate: big then 5
I compared non-null element to 5 and got a bit vector:
0 0 0 0 0 1 1 1 1 1 1 1 1 1
I want to got a bit vector for all elements:
0 0 0 0 0 0 1 0 1 1 0 0 1 1 1 1 1 1
the 0 in bold is null elements, should be false.
void IntersectBitVec(vector<int64_t>& bit_vec, vector<int64_t>& sub_bit_vec) {
int data_idx = 0,
int bit_idx = 63;
for (int i = 0; i < bit_vec.size(); ++i) {
for (int j = 63; j >=0; --j) {
if (bit_vec[i] & 0x01 << j) {
if (!(sub_bit_vec[data_idx] & 0x01 << bit_idx)) {
bit_vec[i] &= ~(0x01 << j);
}
if (--bit_idx < 0) {
--data_idx;
bit_idx = 63;
}
}
}
}}
My code is quite ugly, is there anyway to make it fast? Great thanks!

Eigen Sparse valuePtr is displaing zeros, while leaving out valid values

I don't understand the result I get when I try to iterate over valuePtr of a sparse matrix. Here is my code.
#include <iostream>
#include <vector>
#include <Eigen/Sparse>
using namespace Eigen;
int main()
{
SparseMatrix<double> sm(4,5);
std::vector<int> cols = {0,1,4,0,4,0,4};
std::vector<int> rows = {0,0,0,2,2,3,3};
std::vector<double> values = {0.2,0.4,0.6,0.3,0.7,0.9,0.2};
for(int i=0; i < cols.size(); i++)
sm.insert(rows[i], cols[i]) = values[i];
std::cout << sm << std::endl;
int nz = sm.nonZeros();
std::cout << "non_zeros : " << nz << std::endl;
for (auto it = sm.valuePtr(); it != sm.valuePtr() + nz; ++it)
std::cout << *it << std::endl;
return 0;
}
Output:
0.2 0.4 0 0 0.6 // The values are in the matrix
0 0 0 0 0
0.3 0 0 0 0.7
0.9 0 0 0 0.2
non_zeros : 7
0.2 // but valuePtr() does not point to them
0.3 // I expected: 0.2, 0.3, 0.9, 0.4, 0.6, 0.7, 0.2
0.9
0
0.4
0
0
I don't understand why I am getting zeros, what's going on here?
According to the documentation for SparseMatrix:
Unlike the compressed format, there might be extra space inbetween the
nonzeros of two successive columns (resp. rows) such that insertion of
new non-zero can be done with limited memory reallocation and copies.
[...]
A call to the function makeCompressed() turns the matrix into the standard compressed format compatible with many library.
For example:
This storage scheme is better explained on an example. The following
matrix
0 3 0 0 0
22 0 0 0 17
7 5 0 1 0
0 0 0 0 0
0 0 14 0 8
and one of its possible sparse, column major representation:
Values: 22 7 _ 3 5 14 _ _ 1 _ 17 8
InnerIndices: 1 2 _ 0 2 4 _ _ 2 _ 1 4
[...]
The "_" indicates available free space to quickly insert new elements.
Since valuePtr() simply return a pointer to the Values array, you'll see the empty spaces (the zeroes that got printed) unless you make the matrix compressed.

How to create undirected graph out of adjancency matrix?

Hello everywhere there is an explanation by drawings hot to create graph out of adj. matrix. However, i need simple pseudo code or algorithym for that .... I know how to draw it out of adj. matrix and dont know why nobody no where explains how to actually put it in code. I dont mean actual code but at least algorithm ... Many say .. 1 is if there is an edge i know that.. I have created the adj. matrix and dont know how to transfer it to graph. My vertices dont have names they are just indexes of the matrix. for example 1-9 are the "names of my matrix"
1 2 3 4 5 6 7 8 9
1 0 1 0 0 1 0 0 0 0
2 1 0 1 0 0 0 0 0 0
3 0 1 0 1 0 0 0 0 0
4 0 0 1 0 0 1 0 0 0
5 1 0 0 0 0 0 1 0 0
6 0 0 0 1 0 0 0 0 1
7 0 0 0 0 1 0 0 1 0
8 0 0 0 0 0 0 1 0 0
9 0 0 0 0 0 1 0 0 0
that was originaly a maze ... have to mark row1 col4 as start and row7 col8 end ...
Nobody ever told me how to implement graph out of matrix (without pen) :Pp
thanks
Nature of symmetry
Adjancency matrix is a representation of a graph. For undirected graph, its matrix is symmetrical. For instance, if there is an edge from vertex i to vertex j, there must also be an edge from vertex j to vertex i. That is the same edge actually.
*
*
* A'
A *
*
*
Algorithm
Noticing this nature, you can implement your algorithm as simple as:
void drawGraph(vertices[nRows][nCols])
{
for (unsigned int i = 0; i < nRows; ++i)
{
for (unsigned int j = i; j < nCols; ++j)
{
drawLine(i, j);
}
}
}
You can convert a graph from an adjacency matrix representation to a node-based representation like this:
#include <iostream>
#include <vector>
using namespace std;
const int adjmatrix[9][9] = {
{0,1,0,0,1,0,0,0,0},
{1,0,1,0,0,0,0,0,0},
{0,1,0,1,0,0,0,0,0},
{0,0,1,0,0,1,0,0,0},
{1,0,0,0,0,0,1,0,0},
{0,0,0,1,0,0,0,0,1},
{0,0,0,0,1,0,0,1,0},
{0,0,0,0,0,0,1,0,0},
{0,0,0,0,0,1,0,0,0}
};
struct Node {
vector<Node*> neighbours;
/* optional additional node information */
};
int main (int argc, char const *argv[])
{
/* initialize nodes */
vector<Node> nodes(9);
/* add pointers to neighbouring nodes */
int i,j;
for (i=0;i<9;++i) {
for (j=0;j<9;++j) {
if (adjmatrix[i][j]==0) continue;
nodes[i].neighbours.push_back(&nodes[j]);
}
}
/* print number of neighbours */
for (i=0;i<9;++i) {
cout << "Node " << i
<< " has " << nodes[i].neighbours.size() <<" outbound edges." << endl;
}
return 0;
}
Here, the graph is represented as an array of nodes with pointers to reachable neighbouring nodes. After setting up the nodes and their neighbour pointers you use this data structure to perform the graph algorithms you want, in this (trivial) example print out the number of outbound directed edges each node has.