simple multiplication or operator issue - c++

I am trying to run this simple code. But I am missing something. I tried to look at operator overloading. Could someone explain what I am missing here.
#include <iostream>
#include <vector>
#include <cstdlib>
int main(){
std::vector < std::vector<double> > tm;
std::vector<int> dfg;
// Creating a simple matrix
double ta1[]={0.5,0.5,0};
std::vector <double> tv1 (ta1, ta1+3);
tm.push_back(tv1);
double ta2[]={0.5,0,0};
std::vector <double> tv2 (ta2, ta2+3);
tm.push_back(tv2);
double ta3[]={0,0.5,0};
std::vector <double> tv3 (ta3, ta3+3);
tm.push_back(tv3);
double d_load =0.5;
// doing some simple calculations
for (int destinationID = 1; destinationID <= tm.size(); destinationID++){
float randomNum = ((double) rand())/((double) RAND_MAX);
if (randomNum <= d_load * tm[destinationID - 1])
dfg.push_back(destinationID);
}
return 0;
}
I get the following error.
error: no match for ‘operator*’ in ‘d_load * tm.std::vector<_Tp, _Alloc>::operator[] [with _Tp = std::vector<double>, _Alloc = std::allocator<std::vector<double> >, std::vector<_Tp, _Alloc>::reference = std::vector<double>&, std::vector<_Tp, _Alloc>::size_type = long unsigned int](((long unsigned int)(destinationID + -0x00000000000000001)))’

The tm is a std::vector<std::vector<double>>, thus effectively it is a 2-dimensional dynamic array of double. This means that to access the individual double elements in tm, you would use something like this:
double value = tm[destinationID - 1][theValueIndex];
It is the [theValueIndex] part of the loop that you're missing.
Since we don't know your exact intentions on how you want to traverse the array, I leave it to you to fill in this gap.

The following line is invalid:
d_load * tm[destinationID - 1]
Since tm is a std::vector<std::vector<double>>, The elements of tm are std::vector<double>, not double. If you want to multiply each number or check that each number matches the condition, you have to iterate the element you're getting out of tm[]

Related

Slicing Eigen tensor: Error accessing matrices from tensors

I am new to tensor in Eigen and just trying to run simple examples here. This is the code I have it's to access the first matrix in a tensor. Let's say I have a tensor with size ((nz+1),ny,nx), where each matrix in this tensor should have the shape or size of (nz+1)-by-ny. The thing is I can only extract a matrix that returns size ny-by-nz.
The code:
static const int nx = 10;
static const int ny = 10;
static const int nz = 10;
Eigen::Tensor<double, 3> epsilon((nz+1),ny,nx);
epsilon.setZero();
//slicing test: access first matrix in tensor
std::array<long,3> offset = {0,0,0}; //Starting point
std::array<long,3> extent = {1,ny,nx}; //Finish point
std::array<long,2> shape2 = {(ny),(nx)};
std::cout << epsilon.slice(offset, extent).reshape(shape2) << std::endl;
The answer is a matrix with a 10-by-10 size. How can I change this to extract slice and reshape it into a 11x10 matrix instead (11 rows and 10 columns). I tried changing last line to std::array<long,2> shape2 = {(nz+1),(nx)}; but this returns the error:
Eigen::TensorEvaluator<const Eigen::TensorReshapingOp<NewDimensions, XprType>, Device>::TensorEvaluator(const XprType&, const Device&) [with NewDimensions = const std::array<long int, 2>; ArgType = Eigen::TensorSlicingOp<const std::array<long int, 3>, const std::array<long int, 3>, Eigen::Tensor<double, 3> >; Device = Eigen::DefaultDevice; Eigen::TensorEvaluator<const Eigen::TensorReshapingOp<NewDimensions, XprType>, Device>::XprType = Eigen::TensorReshapingOp<const std::array<long int, 2>, Eigen::TensorSlicingOp<const std::array<long int, 3>, const std::array<long int, 3>, Eigen::Tensor<double, 3> > >]: Assertion `internal::array_prod(m_impl.dimensions()) == internal::array_prod(op.dimensions())' failed.
Aborted
How can I change the number of rows in this matrix? Thanks
I was able to fix:
std::array<long,3> offset = {0,0,0}; //Starting point
std::array<long,3> extent = {(nz+1),nx,1}; //Finish point:(row,column,matrix)
std::array<long,2> shape = {(nz+1),(nx)};
std::cout << epsilon.slice(offset, extent).reshape(shape) << std::endl;

Malloc space for a pointer of array in C++

I need to work upon a variable number of fixed-size arrays. More specifically, N points in a K-dimensional space, where I know K beforehand, but I don't know N at compile time.
So I want to use a pointer to the fixed-size array, and allocate space for N K-dimensional points at runtime.
In C, I can allocate the said pointer with malloc. Example test.c below, where dimension is 3 for simplicity:
#include <stdlib.h>
#include <stdio.h>
#define DIMENSIONS 3
typedef float PointKDimensions[DIMENSIONS];
void do_stuff( int num_points){
PointKDimensions *points;
points = malloc(num_points * sizeof(PointKDimensions));
points[5][0] = 0; // set value to 6th point, first dimension
points[5][1] = 1.0; // to second dimension
points[5][2] = 3.14; // to third dimension
return;
}
int main(){
do_stuff(10); // at run-time I find out I have 10 points to handle
return 0;
}
I can compile this with gcc test.c without errors, and run without segmentation faults.
However, if I try to achieve the same behavior with C++ mv test.c test.cpp, followed by g++ test.cpp, I get:
test.cpp: In function ‘void do_stuff(int)’:
test.cpp:10:18: error: invalid conversion from ‘void*’ to ‘float (*)[3]’ [-fpermissive]
10 | points = malloc(num_points * sizeof(float) * DIMENSIONS);
| ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| void*
Searching up, I found that C++ does not do implicit conversions for malloc, so I changed the malloc to:
points = (float*) malloc(num_points * sizeof(float) * DIMENSIONS);
And then the error becomes:
test.cpp: In function ‘void do_stuff(int)’:
test.cpp:10:12: error: cannot convert ‘float*’ to ‘float (*)[3]’ in assignment
10 | points = (float*) malloc(num_points * sizeof(float) * DIMENSIONS);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| float*
But I could not find a way to do the appropriate cast/conversion to solve this error. E.g., (float**) is also not the same as float(*)[3].
Any suggestions on how to allocate space for a pointer to fixed-sized arrays in C++?
You need to cast the result of malloc as PointKDimensions* not as a float*:
typedef float PointKDimensions[DIMENSIONS];
void do_stuff( int num_points){
PointKDimensions *points;
points = (PointKDimensions*)malloc(num_points * sizeof(PointKDimensions));
points[5][0] = 0; // set value to 6th point, first dimension
points[5][1] = 1.0; // to second dimension
points[5][2] = 3.14; // to third dimension
return;
}
Or better, use C++'s built-in container for dynamically sized arrays, std::vector:
vector<vector<float>> points;
void do_stuff( int num_points){
points.resize(num_points, vector<float>(k)); // assuming k = number of dimensions.
points[5][0] = 0; // set value to 6th point, first dimension
points[5][1] = 1.0; // to second dimension
points[5][2] = 3.14; // to third dimension
return;
}
You could use std:array for that.
e.g.
#include <array>
inline constexpr const size_t DIMENSIONS = 3;
using PointKDimensions = std::array<float, DIMENSIONS>;

Eigen c++ cast double to long int?

Quick question:
consider this (wrong) casting from a double to a long int:
Eigen::VectorXd Price = Map<VectorXd>(price, n);
double TickFactor = 1.0 / TickSize;
Eigen::VectorXi IntPrice = (Price * TickFactor).cast <long int> ();
which gives the following error (Eigen 3.3.5, g++ 7.3.0):
eigen/Eigen/src/Core/util/StaticAssert.h:33:40: error: static assertion failed: YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY
#define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG);
Now, this compiles:
Eigen::VectorXi IntPrice = (Price * TickFactor).cast <int> ();
here is my question. Does the line above allows for values of (Price * TickFactor) that are larger than the upper limit on a short int? --whatever that is on the current system, say 33K.
This line
Eigen::VectorXi IntPrice = (Price * TickFactor).cast <int> ();
is essentially equivalent to
Eigen::VectorXi IntPrice(Price.size());
for(Eigen::Index i=0; i<Price.size(); ++i)
IntPrice[i] = static_cast<int>(Price[i] * TickFactor;
Unless on your system short int and int are the same, you are limited to the size of int (not short int), and the behavior for overflows is (I think) undefined.
If you want 64bit integers, do as ggael suggested:
typedef Eigen::Matrix<int64_t,Dynamic,1> VectorXi64;
VectorXi64 IntPrice = (Price * TickFactor).cast<int64_t>();

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;
}

no match for 'operator =' for 3d vector

I am trying to convert a vector of coordinates std::vector surface into a 3D array, setting all entries of the 3d array that are contained in surface to 0;
however I am getting a no match for operator array.
I looked up the error several times but did not find my case....
std::vector<coordinates> surface is global.
the coordiantes simply look like
struct coords{
int xvalue;
int yvalue;
int zvalue;
coords(int x1, int y1, int z1) : xvalue(x1),yvalue(y1),zvalue(z1){}
~coords(){}
};
typedef struct coords coordinates;
and my method is:
(doubleBox is a typedef for a 3D double vector)
doubleBox levelset::putIntoBox( vector<coordinates> surface){
int xMaxs, yMaxs,zMaxs;
for (vector<coordinates>::iterator it = surface.begin() ; it != surface.end(); ++it){
if (it->xvalue > xMaxs)
xMaxs = it->xvalue;
if (it->yvalue > yMaxs)
yMaxs = it->yvalue;
if (it->zvalue > zMaxs)
zMaxs = it->zvalue;
//check invalid surface
if (it->xvalue < 0 || it->yvalue <0 || it->zvalue<0)
cout << "invalid surface with point coordinates below 0 !" << endl;
}
doubleBox surfaceBox[xMaxs+1][yMaxs+1][zMaxs+1];
int max = std::ceil(sqrt(xMaxs*xMaxs + yMaxs*yMaxs + zMaxs*zMaxs));
std::fill(&surfaceBox[0][0][0],&surfaceBox[0][0][0] + sizeof(surfaceBox)*sizeof(surfaceBox[0])/ sizeof(surfaceBox[0][0]) / sizeof(surfaceBox[0][0]), max);
for (vector<coordinates>::iterator it = surface.begin() ; it != surface.end(); it++){
surfaceBox[it->xvalue][it->yvalue][it->zvalue] = 0.0;
}
return surfaceBox;
}
the output is (declaring that the error lies in the second for-loop)
c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\vector.tcc:160:5: note: std::vector<_Tp, _Alloc>& std::vector<_Tp, _Alloc>::operator=(const std::vector<_Tp, _Alloc>&) [with _Tp = std::vector<std::vector<double> >; _Alloc = std::allocator<std::vector<std::vector<double> > >]
vector<_Tp, _Alloc>::
^
c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\vector.tcc:160:5: note: no known conversion for argument 1 from 'const int' to 'const std::vector<std::vector<std::vector<double> > >&'
..\src\Levelset.cpp: In member function 'doubleBox levelset::putIntoBox(std::vector<coords>)':
..\src\Levelset.cpp:295:1: warning: control reaches end of non-void function [-Wreturn-type]
Maybe this problem is caused by the fact that std::fill is used inappropriately??
Since doubleBox is defined as std::vector<std::vector<std::vector<double>, why do you define doubleBox surfaceBox[xMaxs+1][yMaxs+1][zMaxs+1]; in this way?
What you defined is a 3 dimensional array whose element type is doubleBox, which means that every element is of type std::vector<std::vector<std::vector<double>, which is not what you want.
You may need something like doubleBox surfaceBox(xMaxs + 1, std::vector<std::vector<double>>(yMaxs + 1, std::vector<double>(zMaxs + 1)));