How to customize range of setRandom? - c++

Eigen provides facilities to play with Matrices, and vectors (where one dimension is 1). I'm trying to develop a function which fills a vector (double *array) with random numbers made by setRandom.
double *gen_random(int size, double min, double max) {
double *array = new double[size * sizeof(double)];
Matrix<double, Dynamic, Dynamic, RowMajor>::Map(array, size, 1).setRandom();
return array;
}
The code above does that but random range is [-1:1] as per https://eigen.tuxfamily.org/dox/classEigen_1_1PlainObjectBase.html#title35.
How do I change range to i.e. [0:99]?
Answer and comments so far seems to suggest adding a loop to obtain the desired result, like:
double *gen_random(int size, double min, double max) {
double *array = new double[size * sizeof(double)];
Matrix<double, Dynamic, Dynamic, RowMajor>::Map(array, size, 1).setRandom();
for (int i = 0; i < size; ++i)
array[i] = (array[i]+1)*50;
return array;
}

Here is a complete, single line, solution:
double *gen_random(int size, double min, double max) {
double *array = new double[size * sizeof(double)];
ArrayXd::Map(array,size) = (ArrayXd::Random(size)+1.)*0.5*(max-min) + min;
return array;
}
I'm using Array instead of linear-algebra Vector or Matrix to enable addition with a scalar.

As suggested in the comments, you should probably just perform arithmetic to get your random values into the desired range (i.e. +1, then * 50). This is basically what would happen with a different requested range anyway.

Related

Assigning pre-allocated array to pointer in class constructor C++

I am working on a project for my advanced CFD class, in which we have to solve the heat equation over a curvilinear mesh. I am trying to create an object which will store all of my data, to allow me to visualize it easily later on. This object is created using a class called Solution. Solution contains 8 public variables, all of which are double precision, *x, *y, *u, *v, *T, nx, ny and N, where x and y store the coordinates for each point, u and v the velocities for each point, T stores the temperature for each point, nx and ny store the number of grid points in the x and y direction, and finally N stores the total number of grid points. I have 3 constructors, the first of which initializes the object with all null pointers or values of 0.
Solution::Solution() : X(nullptr), Y(nullptr), u(nullptr), v(nullptr), T(nullptr), nx(0), ny(0), N(0)
The second constructor takes a value for nx and ny, calculates the number of points, allocates memory for each of the arrays, and initializes their values to 0.
// Constructor to initialize solution struct with 0 values
Solution::Solution(unsigned long iNx, unsigned long iNy) : X(nullptr), Y(nullptr), u(nullptr), v(nullptr), T(nullptr), nx(iNx), ny(iNy)
{
N = nx * ny; // Total number of grid points
// Allocate memory for solution variables
O.alloc1D(&X, N);
O.alloc1D(&Y, N);
O.alloc1D(&u, N);
O.alloc1D(&v, N);
O.alloc1D(&T, N);
// Initialize variables values to 0
for(int i = 0; i < N; i++)
{
X[i] = 0.0;
Y[i] = 0.0;
u[i] = 0.0;
v[i] = 0.0;
T[i] = 0.0;
}
}
Where I am having trouble is for my 3rd constructor, in which I hope to create the object using pre-defined arrays.
// Constructor to initialize solution struct using vectors that already exist
Solution::Solution(unsigned long iNx, unsigned long iNy, double *iX, double *iY, double *iu, double *iv, double *iT) :
X(iX), Y(iY), u(iu), v(iv), T(iT), nx(iNx), ny(iNy)
I am having issues figuring out how to assign the arrays to these values. Looking at just X, if I try to implement an array
double x[4] = {1.0, 2.0, 3.0, 4.0};
for X in the constructor it gives me an error as it cannot assign a double to double*. If I try to write
double *x[4] = {1.0, 2.0, 3.0, 4.0};
it gives me an error as it cannot assign double to double* for each value in the array. If I try
double *x;
double x1[4] = {1, 2, 3, 4};
x = &x1;
it gives me an error because it cannot convert double(*)[4] to double in initialization. I feel like there is an easy solution to let me construct my Solution object with arrays that are already defined, but I'm getting stuck. Thank you for your help.

Why is my code throwing a SIGBUS error, even when I store variables in heap?

In the method plotThermalNoise() of the Antenna class, for some reason the for loop does not run. Initially, I used int for n and i, however I need to work with much larger numbers than int can hold. SO, now I'm using a long int for both. The program no longer works, however. I stepped through it with GDB, and it seems I'm getting a SIGBUS error. I tried using new so as to store both variables in heap, however the loop still doesn't run.
#define k 0.0000000000000000000000138064852 //Boltzmann's constant
class Antenna{
double _srate, _sdur, _res, _temp, _band;
public:
Antenna(double sampling_rate, double sample_duration, double resistance_ohms, double temperature_kelvin, double bandwidth_Hz){
_srate = sampling_rate; _sdur = sample_duration;
_res = resistance_ohms; _temp = temperature_kelvin;
_band = bandwidth_Hz;
}
void plotThermalNoise();
};
void Antenna::plotThermalNoise(){
//calculate RMS, mean of Gaussian
double RMS = sqrt(4 * _res * k * _temp * _band);
double V = sqrt((4 * k * _temp * _band) / _res);
long int n = _srate / _sdur;
double x[*n],y[*n];
gRandom->SetSeed(time(NULL));
for(long int i = 0; i < n; ++i){
x[i] = i;
y[i] = gRandom->Gaus(V,RMS);
}
TGraph gr = new TGraph(n,x,y);
gr->SetTitle("Thermal Noise Voltage vs Time Trace;Seconds;Volts");
gr->Draw();
}
void dataAquisitionSim(){
Antenna test(4000000000, 0.000001, 50, 90, 500);
test.plotThermalNoise();
}
long int n = _srate / _sdur;
double x[*n],y[*n];
This code will not compile. I assume your actual code is:
long int n = _srate / _sdur;
double x[n],y[n];
With the parameters you pass in: 4000000000 for _srate and 0.000001 for _sdur, n becomes 4,000,000,000 / 0.000,000,1 == 4,000,000,000,000,000.
You then attempt to allocate two double arrays of that size on stack. The total size of these arrays is 64 peta-bytes.
The largest super-computer currently in existence has "over 10PiB of memory". So you only need something mere 6 times larger than that.
it seems I'm getting a SIGBUS error.
As you should. Some back of the envelope calculations should help you realize that just because your code compiles doesn't mean it will run.
even when I store variables in heap?
Unless you actually have a computer with more than 64PiB of RAM, stack vs. heap is irrelevant -- you'll run out of either.

Armadillo SpMat<int> extremely slow compared to Mat<int>

I am trying to utilize sparse matrices in Armadillo, and am noticing a significant difference in access times with SpMat<int> compared to equivalent code using Mat<int>.
Description:
Below are two methods, which are identical in every respect except that Method_One uses regular matrices and Method_Two uses sparse matrices.
Both methods take following arguments:
WS, DS: Pointers to a NN dimensional array
WW: 13 K [max(WS)]
DD: 1.7 K [max(DS)]
NN: 2.3 M
TT: 50
I am using Visual Studio 2017 for compiling the code into a .mexw64 executable which can be called from Matlab.
Code:
void Method_One(int WW, int DD, int TT, int NN, double* WS, double* DS)
{
Mat<int> WP(WW, TT, fill::zeros); // (13000 x 50) matrix
Mat<int> DP(DD, TT, fill::zeros); // (1700 x 50) matrix
Col<int> ZZ(NN, fill::zeros); // 2,300,000 column vector
for (int n = 0; n < NN; n++)
{
int w_n = (int) WS[n] - 1;
int d_n = (int) DS[n] - 1;
int t_n = rand() % TT;
WP(w_n, t_n)++;
DP(d_n, t_n)++;
ZZ(n) = t_n + 1;
}
return;
}
void Method_Two(int WW, int DD, int TT, int NN, double* WS, double* DS)
{
SpMat<int> WP(WW, TT); // (13000 x 50) matrix
SpMat<int> DP(DD, TT); // (1700 x 50) matrix
Col<int> ZZ(NN, fill::zeros); // 2,300,000 column vector
for (int n = 0; n < NN; n++)
{
int w_n = (int) WS[n] - 1;
int d_n = (int) DS[n] - 1;
int t_n = rand() % TT;
WP(w_n, t_n)++;
DP(d_n, t_n)++;
ZZ(n) = t_n + 1;
}
return;
}
Timing:
I am timing both methods using wall_clock timer object in Armadillo. For example,
wall_clock timer;
timer.tic();
Method_One(WW, DD, TT, NN, WS, DS);
double t = timer.toc();
Results:
Timing elapsed for Method_One using Mat<int>: 0.091 sec
Timing elapsed for Method_Two using SpMat<int>: 30.227 sec (almost 300 times slower)
Any insights into this are highly appreciated!
UPDATE:
This issue has been fixed with newer version (8.100.1) of Armadillo.
Here are the new results:
Timing elapsed for Method_One using Mat<int>: 0.141 sec
Timing elapsed for Method_Two using SpMat<int>: 2.127 sec (15 times slower, which is acceptable!)
Thanks to Conrad and Ryan.
As hbrerkere already mentioned, the problem stems from the fact that the values of the matrix are stored in a packed format (CSC) that makes it time-consuming to
Find the index of an already existing entry: Depending on whether the column entries are sorted by their row index you need either linear or binary search.
Insert a value that was previously zero: Here you need to find the insertion point for your new value and move all elements after that, leading to Ω(n) worst case time for a single insertion!
All these operations are constant-time operations for dense matrices, which mostly explains the runtime difference.
My usual solution was to use a separate sparse matrix type for assembly (where you usually access an element multiple times) based on the coordinate format (storing triples (i, j, value)) that uses a map like std::map or std::unordered_map to store the triple index corresponding to a position (i,j) in the matrix.
Some similar approaches are also discussed in this question about matrix assembly
Example from my most recent use:
class DynamicSparseMatrix {
using Number = double;
using Index = std::size_t;
using Entry = std::pair<Index, Index>;
std::vector<Number> values;
std::vector<Index> rows;
std::vector<Index> cols;
std::map<Entry, Index> map; // unordered_map might be faster,
// but you need a suitable hash function
// like boost::hash<Entry> for this.
Index num_rows;
Index num_cols;
...
Number& value(Index row, Index col) {
// just to prevent misuse
assert(row >= 0 && row < num_rows);
assert(col >= 0 && col < num_cols);
// Find the entry in the matrix
Entry e{row, col};
auto it = map.find(e);
// If the entry hasn't previously been stored
if (it == map.end()) {
// Add a new entry by adding its value and coordinates
// to the end of the storage vectors.
it = map.insert(make_pair(e, values.size())).first;
rows.push_back(row);
cols.push_back(col);
values.push_back(0);
}
// Return the value
return values[(*it).second];
}
...
};
After assembly you can store all the values from rows, cols, values (which actually represent the matrix in Coordinate format), possibly sort them and do a batch insertion into your Armadillo matrix.
Sparse matrices are stored in a compressed format (CSC). Every time a non-zero element inserted into a sparse matrix, the entire internal representation has to be updated. This is time consuming.
It's much faster to construct the sparse matrix using batch constructors.

How to set SparseMatrix.valuePtr(), SparseMatrix.outerIndexPtr() and SparseMatrix.innerIndexPtr() for CSR Format?

I already have my sparse matrix data in CSR format, ie: I already have data for non zero values ( in the form of double[]), the row and the column index ( both in the form of int[]) of the non zero values.
My problem is, how can I assign them directly to Sparse Matrix in eigen library? I know that the relevant fields in Sparse Matrix are valuePtr, outerIndexPtr and innerIndexPtr, but I can't set the pointer directly as per below:
//the relevant SpMat fields (valuePtr,outerIndexPtr,innerIndexPtr) are not able to set
static SpMat CSRFormat2(double* nonZeroPtr, int* rowIndex,
int* colIndex, int totDOF, int nonZeroCount)
{
SpMat sparseMatrix = SpMat(totDOF,totDOF);
double *nonZ=sparseMatrix.valuePtr();
nonZ=nonZeroPtr;
int *outerIndex = sparseMatrix.outerIndexPtr();
outerIndex=rowIndex;
int *innerIndex = sparseMatrix.innerIndexPtr();
innerIndex = colIndex;
sparseMatrix.reserve(nonZeroCount);
return sparseMatrix;
}
I don't want to iterate over the non zero values and set everything again. That would be inefficient, I think.
How to set SparseMatrix.valuePtr(), SparseMatrix.outerIndexPtr() and SparseMatrix.innerIndexPtr(), if this is possible at all?
This is a hack that I haven't really tested (recently). It does copy the values, however:
SparseMatrix<double, whatever, indexType> m;
m.resize(rows, cols);
m.makeCompressed();
m.resizeNonZeros(nnz);
memcpy((void*)(m.valuePtr()), (void*)(valueSrc), sizeof(double) * nnz);
memcpy((void*)(m.outerIndexPtr()), (void*)(outerIndexPtrSrc), sizeof(indexType) * outSz);
memcpy((void*)(m.innerIndexPtr()), (void*)(innerIndexPtrSrc), sizeof(indexType) * nnz);
m.finalize();
If you would rather not copy the memory, then just assigning the pointers (sparseMatrix.valuePtr() = nonZeroPtr;) will cause problems later, as the matrix thinks it owns the memory and will delete it on destruction. You should probably use std::swap instead.
One last note, the index type of the Eigen::SparseMatrix may not be int, so you may want to deal with that before just copying/swapping.
Thanks to the comment from ggael, this is how I solve the problem:
///CSR format: nonZeroArray, rowIndex, colIndex
SparseMatrix<double, Eigen::RowMajor> ConstructSparseMatrix(int rowCount, int colCount, int nonZeroCount, double *nonZeroArray, int *rowIndex, int *colIndex)
{
Map<SparseMatrix<double, Eigen::RowMajor>> spMap(rowCount, colCount, nonZeroCount, rowIndex, colIndex, nonZeroArray, 0);
SparseMatrix<double, Eigen::RowMajor> matrix= spMap.eval();
matrix.reserve(nonZeroCount);
return matrix;
}

Setting pointer to a double array in for loop

I have an algorithm that I want to run that uses a potentially long double array. Because the array can be millions in length, I'm putting it on the GPU so I need to export the array from a CPP file to a CU file. However, Im prototyping it in CPP only for now because it doesnt work in either case.
In my CPU prototype I get errors when I try to set the members of the double array with my for loop. For example, any operation including cout will give error c2109:subscript requires array or pointer type in the CPP file
or if the same code is run from a CU file, error: expression must have a pointer-to-object type
const int size = 100000;
double inputMeshPts_PROXY[size][4];
inputMeshPts.get(inputMeshPts_PROXY);
int lengthPts = inputMeshPts.length();
if (useCUDA == 1)
{
double *inputMeshPts_CUDA = &inputMeshPts_PROXY[size][4];
myArray(lengthPts, inputMeshPts_CUDA);
}
MStatus abjBlendShape::myArray(int length_CUDA, float weight_CUDA, double *inputMeshPts_CUDA)
{
for (int i = 0; i < length_CUDA; i++)
{
for (int j = 0; j < 3; j++)
{
cout << inputMeshPts_CUDA[i][j] << endl;
// inputMeshPts_CUDA[i][j] += (sculptedMeshPts_PROXY[i][j] - inputMeshPts_CUDA[i][j]); // WHAT I WANT, EVENTUALLY
}
}
}
When you are writing:
double *inputMeshPts_CUDA = &inputMeshPts_PROXY[size][4];
The variable inputMeshPts_CUDA is a pure pointer. You cannot use 2-dimensional indexing [][] as before. The right way to access it is now to linearize the indexes:
inputMeshPts_CUDA[i*4+j]
Alternatively you could declare "correctly" your pointer:
double (*inputMeshPts_CUDA)[4] = inputMeshPts_PROXY;
which allows you to use the 2-dimensional indexing again.
MStatus abjBlendShape::myArray(int length_CUDA, float weight_CUDA, double *inputMeshPts_CUDA)
{
inputMeshPts_CUDA is just a pointer, the compiler has lost all the dimension information. It needs that dimension information for inputMeshPts_CUDA[i][j], which gets converted to an access to address (byte arithmetic, not C++ pointer arithmetic)
inputMeshPts_CUDA + i * sizeof (double) * num_colums + j * sizeof (double)
You can either provide the missing information yourself and do the arithmetic like Angew suggests, or have the compiler pass the dimension information through:
template<size_t M, size_t N>
MStatus abjBlendShape::myArray(int length_CUDA, float weight_CUDA, double (&inputMeshPts_CUDA)[M][N])
Of course, this only works when the size is known at compile-time.
inputMeshPts_CUDA is a pointer to double - that is, it can represent a 1D array. You're accessing it as a 2D array: inputMeshPts_CUDA[i][j]. That doesn't make sense - you're effectively applying [j] to the double object storead at inputMeshPts_CUDA[i].
I believe you were looking for inputMeshPts_CUDA[i * 4 + j] - you have to compute the 2D addressing yourself.