How to fill a sparse matrix efficiently? - c++

I use the eigen library to perform the sparse matrix operations, particularly, to fill a sparse matirx. But the rows and cols are very large in our case, which results in a long time for filling the sparse matrix. Is there any efficient way to do this (maybe by the other libraries)?
Below is the my code:
SparseMatrix mat(rows,cols);
mat.reserve(VectorXi::Constant(cols,6));
for each i,j such that v_ij != 0
mat.insert(i,j) = v_ij;
mat.makeCompressed();

The order in which a SparseMatrix is filled can make an enormous difference in computation time. To fill a SparseMatrix matrix quickly, the elements should be addressed in a sequence that corresponds to the storage order of the SparseMatrix. By default, the storage order in Eigen's SparseMatrix is column major, but it is easy to change this.
The following code demonstrates the time difference between a rowwise filling of two sparse matrices with different storage order. The square sparse matrices are relatively small and nominally identical. While the RowMajor matrix is almost instantly filled, it takes a much longer time (about 30 seconds on my desktop computer) in the case of ColMajor storage format.
#include <iostream>
#include <Eigen/Dense>
#include <Eigen/SparseCore>
#include <random>
using namespace Eigen;
typedef SparseMatrix<double, RowMajor> SpMat_RM;
typedef SparseMatrix<double, ColMajor> SpMat_CM;
// compile with -std=c++11 -O3
int main() {
const int n = 1e4;
const int nnzpr = 50;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> randInt(0, n-1);
SpMat_RM m_RM(n,n);
m_RM.reserve(n);
SpMat_CM m_CM(n,n);
m_CM.reserve(n);
std::cout << "Row-wise filling of [" << n << " x " << n << "] sparse matrix (RowMajor) ..." << std::flush;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < nnzpr; ++j) {
int col = randInt(gen);
double val = 1. ; // v_ij
m_RM.coeffRef(i,col) = val ;
}
}
m_RM.makeCompressed();
std::cout << "done." << std::endl;
std::cout << "Row-wise filling of [" << n << " x " << n << "] sparse matrix (ColMajor) ..." << std::flush;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < nnzpr; ++j) {
int col = randInt(gen);
double val = 1.; // v_ij
m_CM.coeffRef(i,col) = val ;
}
}
m_CM.makeCompressed();
std::cout << "done." << std::endl;
}

Related

Stange behaviour using nanoflann

Using the nanoflann-library for k-nearest-neighbor searches based on KDTrees I encountered a very strange behavior. My Code is a simple set of queries:
#include <vector>
#include <iostream>
#include <nanoflann.hpp>
#include <eigen3/Eigen/Dense>
using Eigen::MatrixX3d;
using Eigen::Vector3d;
using nanoflann::KNNResultSet;
using nanoflann::SearchParams;
using kdt = nanoflann::KDTreeEigenMatrixAdaptor<MatrixX3d, 3, nanoflann::metric_L2>;
int main()
{
// Create simple matrix
MatrixX3d matrix(10, 3);
for(unsigned int i = 0; i < 10; i++)
{
double f_i = static_cast<double>(i);
matrix.row(i) = Vector3d(f_i, 0, 0);
}
// Create test points
std::vector<Vector3d> test_vecs;
for(unsigned int i = 0; i < 10; i++)
{
double f_i = static_cast<double>(i);
test_vecs.push_back(Vector3d(f_i, f_i, f_i));
}
// Result buffer
double distance;
size_t index;
KNNResultSet<double> result_set(1);
result_set.init(&index, &distance);
SearchParams sp;
// KDTree
kdt matrix_index(3, std::ref(matrix), 10);
matrix_index.index->buildIndex();
//Query points backwards
for(int i = 9; i >= 0; i--)
{
Vector3d curr_vec = test_vecs.at(i);
matrix_index.index->findNeighbors(result_set, &curr_vec[0], sp);
std::cout << i << std::endl;
std::cout << index << " " << distance << std::endl << std::endl;
}
// Query points forwards
for(unsigned int i = 0; i < 10; i++)
{
Vector3d curr_vec = test_vecs.at(i);
matrix_index.index->findNeighbors(result_set, &curr_vec[0], sp);
std::cout << i << std::endl;
std::cout << index << " " << distance << std::endl << std::endl;
}
}
The backward query (BQ) returns the expected results. However the forward query (FQ) only yields zeros (both index and distance). FQ also seems to break the KDTree altogether. If you change the order of the two queries (the last two for loops), so that FQ is performed before BQ both will now only yield zeros.
Why does that behavior occur and how to circumvent it?
The result set appears to be stateful - it's always showing you the nearest overall neighbor of all the points. For instance, if you loop from 5 to 10 you get 5 50 for each iteration
Reinitialize the result set each iteration and you'll get your desired behavior:
result_set.init(&index, &distance);
matrix_index.index->findNeighbors(result_set, &curr_vec[0], sp);
Demo: https://godbolt.org/z/s5f1jq

How to find a minimum and maximum value in a 2D array ROW?

I have a program that generates 10 rows and 5 columns and the user inputs data. My question is, how can I find the maximum and lowest values in each row? I have been working on this for a good hour but cannot figure this out. I have attempted to solve this many times; here is my current code.
#include <iostream>
#include <iomanip>
using namespace std;
int returnMax(int[][]);
int main()
{
double sales[10][5];
string name[10];
double highest;
double lowest;
double avg;
// Populating table
for (int row = 0; row < 1; row++)
{
cout << "Enter the salesman's name: " << endl;
cin >> name[row];
cout << "Enter the amount of sales for the five years" << endl;
for (int col = 0; col < 5; col++) {
cin >> sales[row][col];
}
}
cout << returnMax(sales[1][0]) << endl;
return 0;
}
int returnMax(int a[][])
{
int max;
for (int i = 0; i < 1; i++) {
max = a[i][0];
for (int j = 0; j < 5; j++) {
if (a[i][j] > max)
max = a[i][j];
}
}
return max;
}
Your logic here:
cout << returnMax(sales[1][0]) << endl;
is wrong. The sales[1][0] is only a single element of entire sales array. That means,
sales[1][0] = element of 1st row and 0th column in sales array in which you did not have any values initilized. Because you have initilzed only one single row in your entire array as you have the line:
for (int row = 0; row < 1; row++)
Remember in C++ indexing starts from 0 not from 1. That being said, the above result(uninitialized variables) will lead you to have undefined behavior.
Suggestions:
In modern C++ you have better options than using raw arrays. For
example, use of
std::vector<>
or std::array<>
makes your code both simpler and safer. In your case, you can either
have
std::vector<int> sales(50, 0) // one dimentional: with 10 * 5 entries
and manipulate the rows accordingly(see solution-1) or
std::vector<std::vector<int>> sales(10, std::vector<int>(5, 0));
// two dimensional: with 10 rows and 5 columns
and use range-based for loops so that, you never end up with
out of bounds problems(see solution-2).
Regarding finding the min and max of each row entries, you can
simply apply algorithm function called
std::minmax_element
from algorithm header.
Sample solution - 1
A sample solution using one-dimensional vector array would look like this: SEE LIVE
#include <iostream>
#include <vector> // std::vector
#include <algorithm> // std::minmax_element
#include <string>
int main()
{
constexpr std::size_t rawMax = 2;
constexpr std::size_t colMax = 5;
// one dimentional array with size = (rawMax * colMax)
std::vector<int> sales(rawMax * colMax, 0);
std::vector<std::string> name(rawMax);
// Populating table
for (std::size_t row = 0; row < rawMax; ++row)
{
std::cout << "Enter the salesman's name: "; std::cin >> name[row];
std::cout << "Enter the amount of sales for the five years: " ;
for (std::size_t col = 0; col < colMax; ++col)
std::cin >> sales[(row*colMax) + col]; // convert col and raw to 1D index.
}
/// get the begin and end of each row as iterators
auto rowBeginIter = sales.begin();
auto rowEndIter = sales.begin() + colMax - 1;
for (const std::string& str: name)
{
std::cout << "salesman's name: "; std::cout << str;
auto getMinMaxRow = std::minmax_element(rowBeginIter, rowEndIter + 1);
std::cout << " min: " << *getMinMaxRow.first
<< " max: " << *getMinMaxRow .second << std::endl;
rowBeginIter += colMax; // increment both iterator to the next raw
rowEndIter += colMax;
}
return 0;
}
Sample solution - 2
A sample solution using a vector of vectors(2D) would look like this: SEE LIVE
#include <iostream>
#include <vector> // std::vector
#include <algorithm> // std::minmax_element
#include <string>
int main()
{
constexpr std::size_t rawMax = 2; // to test
constexpr std::size_t colMax = 5;
// initilize thw 2D vector of vectors with (rawMax x colMax)
std::vector<std::vector<int>> sales(rawMax, std::vector<int>(colMax, 0));
// initilize with 0's with a size that of maximum number of rows.
std::vector<std::string> name(rawMax, "");
// Populating table
for (std::size_t row = 0; row < rawMax; row++)
{
std::cout << "Enter the salesman's name: "; std::cin >> name[row];
std::cout << "Enter the amount of sales for the five years: " ;
for (std::size_t col = 0; col < colMax; col++) {
std::cin >> sales[row][col];
}
}
/* print max and min of each person
* use range based for loops to loop through them
* (optional: index based loops can also be used like above)
*/
auto nameIter = name.cbegin();
for(const std::vector<int>& each_row: sales)
{
std::cout << "salesman's name: "; std::cout << *nameIter << "\t";
auto getMinMaxRow = std::minmax_element(each_row.cbegin(), each_row.cend());
std::cout << " min: " << *getMinMaxRow.first
<< " max: " << *getMinMaxRow.second << std::endl;
++nameIter; // increment the iterator of name-vector
}
return 0;
}
First of all, prepare your environment this way:
#define NROWS 10 //use a constant for number of rows
#define NCOLUMNS 5 // use a constant for number of columns
typedef int Matrix[NROWS][NCOLUMNS]; // declare the type Matrix which is 2d Array using NROWS and NCOLUMNS as size
int returnMaxForRow(int,Matrix); //If you want to know the max value of a row, you need to pass the row
so in the main you can do:
int main () {
Matrix sales; //You don't need to specify the size, which is done before
string name[10];
double highest;
double lowest;
double avg;
ecc....
Now your function should do this:
int returnMaxForRow (int row, Matrix a) {
int max = a[row][0];
for (int i = 0; i < NCOLUMNS; i++) {
if (a[row][i] > max){
max = a[row][i];
}
}
return max;
}
so you can call it this way:
cout<< returnMaxForRow(0,sales);
cout<< returnMaxForRow(1,sales);
cout<< returnMaxForRow(2,sales);
cout<< returnMaxForRow(3,sales);
Some Advices:
Use constants or variable to set array's index, such as define statement
When you do sales[1][0] you get a single value (row 1, column 0) and not all the row
Use typedef to declare custom array with different dimensions, it is easier to handle them this way
If you want, you can change the function to return all the max of all the rows.
If you want to get the max of the matrix, the approach is similar.

Sorting multiple vectors according to one vector [duplicate]

This question already has answers here:
Sorting zipped (locked) containers in C++ using boost or the STL
(5 answers)
Closed 1 year ago.
I have four vectors containing x, y, radius and weight information on centres of circles. I would like to sort them in order of weight (highest to lowest), but I really have no idea how or where to start with this. I could put all the vectors in an Eigen::Tensor to keep the data gathered in one 4d matrix if that would help. But other than that I don't know.
Each of the vectors contain 134 elements, but since it's only one of them having to be sorted that means the sorting algorithm doesn't matter all that much.
Does anyone have a hint on where to start?
You can create a 5th vector of indices, sort the vector of indices according to one of the 4 vectors, then reorder all 4 vectors (and also sort the vector of indices) in O(n) time. Example to sort 3 vectors according to one of them (the ages vector). The vector of indices I is created then sorted according to A (using lambda compare), then all 3 vectors and I are reordered according to I by undoing the "cycles" in I.
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
int main()
{
std::vector <int> A; // ages
std::vector <std::string> N; // names
std::vector <int> Z; // zip codes
std::vector <size_t> I; // indices
int tA;
std::string tN;
int tZ;
A.push_back(37);
N.push_back("Ted");
Z.push_back(54211);
A.push_back(21);
N.push_back("John");
Z.push_back(53421);
A.push_back(31);
N.push_back("Fred");
Z.push_back(52422);
A.push_back(21);
N.push_back("Sam");
Z.push_back(51422);
// display the vectors
for(size_t i = 0; i < A.size(); i++)
std::cout << std::setw(6) << N[i]
<< std::setw(8) << Z[i]
<< std::setw(4) << A[i] << std::endl;
std::cout << std::endl;
// initialize the vector of indices
for(size_t i = 0; i < A.size(); i++)
I.push_back(i);
// sort I according to A
std::stable_sort(I.begin(), I.end(),
[&A](size_t i, size_t j) {return
A[i] < A[j];});
// reorder A, N, Z in place also restore I
// time complexity is O(n)
for(size_t i = 0; i < A.size(); i++){
size_t j, k;
if(i != I[i]){
tA = A[i];
tN = N[i];
tZ = Z[i];
k = i;
while(i != (j = I[k])){
A[k] = A[j];
N[k] = N[j];
Z[k] = Z[j];
I[k] = k;
k = j;
}
A[k] = tA;
N[k] = tN;
Z[k] = tZ;
I[k] = k;
}
}
// display the sorted vectors
for(size_t i = 0; i < A.size(); i++)
std::cout << std::setw(6) << N[i]
<< std::setw(8) << Z[i]
<< std::setw(4) << A[i] << std::endl;
return 0;
}
With ranges-v3, you may do something like
ranges::sort(
ranges::view::zip(xs, ys, radiuses, weights),
std::greater<>{}, // decreasing order
[](const auto& t){ return std::get<3>(t); }); // Projection: use weight
Demo
But having class Circle would make sense, that would avoid to zip the arrays, and allow to have a shorter projection.
Perhaps it makes more sense to first restructure your code and convert four vectors into one vectors of structures.
Something like that:
struct CircleInfo
{
int x, y, radius, weight;
};
std::vector<CircleInfo> circles;
Then, if you want to sort by radius:
#include <vector>
#include <algorithm>
#include <iostream>
struct CircleInfo
{
int x, y, radius, weight;
};
int main()
{
std::vector<CircleInfo> circles;
CircleInfo ci1 = { 1,1,1,1 };
CircleInfo ci2 = { 3,3,3,3 };
circles.push_back(ci2);
circles.push_back(ci1);
std::cout << "before sort circles[0].radius: " << circles[0].radius << std::endl;
std::sort(circles.begin(), circles.end(), [](const CircleInfo& c1, const CircleInfo& c2) {
return c1.radius < c2.radius;
});
std::cout << "aftern sort circles[0].radius: " << circles[0].radius << std::endl;
}
Output:
before sort circles[0].radius: 3
after sort circles[0].radius: 1
This code uses std::sort with custom function that compares two circles. To compare by radius you'd need to update it to compare c1.weight with c2.weight.

Using structs / genetic algorithm

As practice for myself I'm trying to create a genetic algorithm that will solve equations. So far my program can generate random "genes", fill up individuals with these "genes", and do some basic calculations with the genes (at the moment, simply summing the "genes").
However, I've realised now that I want to implement my fitness function that I would have been better off creating a struct for individual, since I need to keep the genes and the fitness outcome together to have the fittest genes reproduce again.
Anyway, here's my code:
// GA.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <random>
#include <string>
const int population_size = 10;
const int number_of_variables = 7;
struct one_individual
{
std::vector<std::vector<double>>individual;;
double evaluation = 0;
double fit = 0;
};
int main()
{
// Generate random number
std::random_device rd;
std::mt19937 rng(rd()); // random-number engine (Mersenne-Twister in this case)
std::uniform_real_distribution<double> dist(-10.0, 10.0);
// Create vector that holds vectors called individual and fill size it to the amount of individuals I want to have.
std::vector<std::vector<double>>individual;
for (int i = 0; i < population_size; i++)
{
std::vector<double>variables;
for (int j = 0; j < number_of_variables; j++)
{
variables.push_back(dist(rng));
}
individual.push_back(variables);
}
// Display entire population
for (auto &count : individual)
{
for (auto &count2 : count)
{
std::cout << count2 << " ";
}
std::cout << "\n";
}
// Do calculation with population. At the moment I just add up all the genes (sum) and display the sum for each individual.
for (int i = 0; i < population_size; i++)
{
int j = 0;
std::cout << "Organism "<< i;
double sum = individual[i].at(j) + individual[i].at(j + 1) + individual[i].at(j + 2) + individual[i].at(j + 3) + individual[i].at(j + 4) + individual[i].at(j + 5) + individual[i].at(j + 6);
std::cout << " is " << sum << "\n";
}
std::cout << "\n";
return 0;
}
What I think I should be doing is something like this:
for (int i = 0; i < population_size; i++)
{
one_individual individual;
std::vector<double>variables;
for (int j = 0; j < number_of_variables; j++)
{
variables.push_back(dist(rng));
}
one_individual.individual.push_back(variables);
}
The above code is not working. What happens when I try to compile is I get a list of errors, I just pasted it into pastebin since it's a pretty big list: www.pastebin.com/EVJaV0Ex. If I remove everything except the parts needed for the "creating individuals part" the errors that remain are: www.pastebin.com/djw6JmXZ. All errors are on line 41 which is the final line one_individual.individual.push_back(variables);
Edited for clarity, apologies that it was unclear.
Consider the instruction
one_individual.individual.push_back(variables);
where one_individual is a type (struct one_individual).
I suppose you should use the defined variable of type one_individual, so
individual.individual.push_back(variables);

C++ Unhandled exception for large vector/array

I keep getting an unhandled exception in my code and it has me stumped.
I am sure it is in the way I have my variables declared.
Basically I am attempting to create 3 arrays, M rows, N columns of random variables.
If I set my N = 1,000 and M = 10,000, not a problem.
If I then change M = 100,000 I get an Unhandled exception memory allocation error.
Can someone please help me understand why this is happening.
Parts of the code was written on VS2010. I have now moved on to VS2013, so any additional advice on the usage of newer functions would also be appreciated.
cheers,
#include <cmath>
#include <iostream>
#include <random>
#include <vector>
#include <ctime>
#include <ratio>
#include <chrono>
int main()
{
using namespace std::chrono;
steady_clock::time_point Start_Time = steady_clock::now();
unsigned int N; // Number of time Steps in a simulation
unsigned long int M; // Number of simulations (paths)
N = 1000;
M = 10000;
// Random Number generation setup
double RANDOM;
srand((unsigned int)time(NULL)); // Generator loop reset
std::default_random_engine generator(rand()); // Seed with RAND()
std::normal_distribution<double> distribution(0.0, 1.0); // Mean = 0.0, Variance = 1.0 ie Normal
std::vector<std::vector<double>> RandomVar_A(M, std::vector<double>(N)); // dw
std::vector<std::vector<double>> RandomVar_B(M, std::vector<double>(N)); // uncorrelated dz
std::vector<std::vector<double>> RandomVar_C(M, std::vector<double>(N)); // dz
// Generate random variables for dw
for (unsigned long int i = 0; i < M; i++)
{
for (unsigned int j = 0; j < N; j++)
{
RANDOM = distribution(generator);
RandomVar_A[i][j] = RANDOM;
}
}
// Generate random variables for uncorrelated dz
for (unsigned long int i = 0; i < M; i++)
{
for (unsigned int j = 0; j < N; j++)
{
RANDOM = distribution(generator);
RandomVar_B[i][j] = RANDOM;
}
}
// Generate random variables for dz
for (unsigned long int i = 0; i < M; i++)
{
for (unsigned int j = 0; j < N; j++)
{
RANDOM = distribution(generator);
RandomVar_C[i][j] = RANDOM;
}
}
steady_clock::time_point End_Time = steady_clock::now();
duration<double> time_span = duration_cast<duration<double>>(End_Time - Start_Time);
//Clear Matricies
RandomVar_A.clear();
RandomVar_B.clear();
RandomVar_C.clear();
std::cout << std::endl;
std::cout << "its done";
std::cout << std::endl << std::endl;
std::cout << "Time taken : " << time_span.count() << " Seconds" << std::endl << std::endl;
std::cout << "End Of Program" << std::endl << std::endl;
system("pause");
return 0;
}
// *************** END OF PROGRAM ***************
Three 100,000 x 1,000 arrays of doubles represents 300 million doubles. Assuming 8 byte doubles, that's around 2.3 GB of memory. Most likely your process is by default limited to 2 GB on Windows (even if you have much more RAM installed on the machine). However, there are ways to allow your process to access a larger address space: Memory Limits for Windows.
I'm experienced something similar then my 32-bit application allocates more than 2Gb memory.
Your vectors require about 2.1Gb memory, so it might be same problem.
Try to change platform of your application to x64. This may solve problem.