I am doing some vector computations using the NE10 library. The library has a type for a complex number which is a struct like this:
typedef struct
{
ne10_float32_t r;
ne10_float32_t i;
} ne10_fft_cpx_float32_t;
I would like to have a function, which takes an array of these structs (1D array of complex numbers) as an argument and performs a vector computation for only the r or i elements of the array. Here is an example of such function to get an idea:
void multiple_real_part_by_two(ne10_fft_cpx_float32_t* output,
ne10_fft_cpx_float32_t* input, ne10_uint32_t array_length)
{
ne10_mulc_float_c (&output->r, &input->r, 2.0, array_length)
}
So I would like the output array to be like the input array, but each of the r elements should be multiplied by two. The problem is, the way the function is written above does not work, and leads to a segmentation fault. I think the problem is in how I am trying to pass an array of the r elements to the ne10_mulc_float_c() function.
The ne10_mulc_float_c() function takes as arguments pointers to two arrays of type ne10_float32_t of size array_length. The elements of the input array are multiplied by the number passed as the third argument, and the result is stored in the output array. The documentation can be found here.
Is there a way I could do this? I know I could just do this in a for loop
for (int i = 0; i < array_length; i++) {
output[i].r = input[i].r * 2.0
}
but I don't want to do this since performance is critical, which is why I am trying to use the vector operations provided by NE10 in the first place.
The problem is that you give ne10_mulc_float_c() arguments of the right type, but which do not match the assumptions.
According to the library's documentation page, the function is defined as:
ne10_result_t ne10_mulc_float_c (ne10_float32_t *dst, ne10_float32_t *src,
const ne10_float32_t cst, ne10_uint32_t count)
with the following arguments:
[out] dst Pointer to the destination array
[in] src Pointer to the source array
[in] cst The constant to multiply by
[in] count The number of scalar values to be processed
This means that the function assumes that dst and src are are pointers to arrays of count CONSECUTIVE floating point numbers.
Unfortunately, the is is not the case with the arguments that you pass:
&output->r and &input->r are both pointers to one single float. So as soon at this function tries to access the second item in the array it expects, it code goes beyond the array's real bounds and this is UB. This is why it doesn't work and you get the segmentation fault.
Your for-loop is just fine. Don't forget:
Premature optimization is the root of all evil.
-- Donald Knuth
Related
I've been working on a program where I need to be able to sum rows in a two-dimensional array whose number of columns are variables. I should also add that the rows are "split" into two parts (part A, and part B) whose sizes depend on user input.
I can obviously sum a row just using a for loop, but I wanted a more elegant solution that would also be easier to set up across the whole program. I stumbled across the accumulate function out of the numeric library, but all examples that I was able to find were exclusively for one-dimensional arrays.
Here's a sample of my problem code:
total = partNum[PART_A] + partNum[PART_B];
partStart[PART_A] = 0;
partEnd[FUNC_A] = partNum[PART_A];
partStart[PART_B] = partNum[PART_A];
partEnd[FUNC_B] = total;
double stat[5][total];
double mass_sum = 0.0
func = PART_A;
accumulate(stat[MASS][partStart[func]], stat[MASS][partStart[func]], mass_sum);
However, I get a buildtime error which states that:
Indirection requires pointer operand ('double' invalid')
I assume this is a syntax error, but changing how I defined the array's start and end did nothing to fix the error.
The two first argument of accumulate are iterators that the function will use to iterate over the range, but you are passing actual element of the array
Iterator in C++ is a concept that requires certain operations to be valid on your object, as defined per the standard. For instance, pointer types usually match the LegacyRandomAccessIterator, meaning that you can basically use them to as array-like object (you can increment them with ++, you can indirect them with *, you can access an element at position i with [], etc.). I won't go into full details about what are iterators in C++ because it's a whole topic and you can find plenty of references, in particular on the two links I provided.
Back to your problem, what you want is to give accumulate iterator to the beginning and the end of your row, or the beginning and the end of your subranges. There are two ways to do this:
Take the address of the element stat[MASS][partStart[func]], i.e., &stat[MASS][partStart[func]], which will give you the beginning of the range, and then &stat[MASS][partEnd[func]] will give you the end of the range. This works because stat is as double stat[5][total] and the access operator ([]) gives you a reference (a double&), that you can take the address of, and the element on the row are contiguous in memory (that would not work for a column).
Use stat[MASS] + partStart[func] and stat[MASS] + partEnd[func]. In this case, you take the beginning of the row (stat[MASS]), which is (or is implicitly convertible to) a pointer to double (double*) and you increment that pointer by partStart[func] or partEnd[func], giving you the addresses of the elements you want in the row.
So basically:
std::accumulate(&stat[MASS][partStart[func]], &stat[MASS][partEndfunc]], mass_sum);
// or
std::accumulate(stat[MASS] + partStart[func], stat[MASS] + partEnd[func], mass_sum);
I went through few StackOverflow posts but didn't find such error. I am trying to write a simple class which does a few operations on Eigen vectors and matrices. I created a class called MyClass and it has a method by the name MyMethod. It's code is as follows
void MyClass::MyMethod(Eigen::Vector4f X,
std::vector<Eigen::Vector2i> &pixelIndices,
std::vector<Eigen::Vector4f> vertices)
{
// Do some preprocessing
//Deleacring the std vector
std::vector<Eigen::Vector2i> currTriangle(3);
currTriangle[0] = Eigen::Vector2i(0); //Error occurs here
// Do some more processing
}
Upon executing method from a main function error occurs at the said statement. The error output is given below.
$: ./test1
test1: /usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h:285: void Eigen::PlainObjectBase<Derived>::resize(Eigen::Index) [with Derived = Eigen::Matrix<int, 2, 1>; Eigen::Index = long int]: Assertion `((SizeAtCompileTime == Dynamic && (MaxSizeAtCompileTime==Dynamic || size<=MaxSizeAtCompileTime)) || SizeAtCompileTime == size) && size>=0' failed.
Aborted (core dumped)
I know that using STL containers with Eigen is problematic, but as mentioned in the documentation the problems seems to be only with fixed size vectorizable Eigen types (that is they should be of 16 byte size), but Vector2i is not such a Eigen type. The assert statement is called in resize() method of PlainObjectBase, which is also weird because I haven't used it anywhere in the code.
Has anyone else faced this error? Any help will be really appreciated.
Update:
The error seems to be not because I used std::vector. I made this small changes to the code.
void MyClass::MyMethod(Eigen::Vector4f X,
std::vector<Eigen::Vector2i> &pixelIndices,
std::vector<Eigen::Vector4f> vertices)
{
// Do some preprocessing
Eigen::Vector2i temp(0); //Same Error occures here also
//Deleacring the std vector
std::vector<Eigen::Vector2i> currTriangle(3);
currTriangle[0] = Eigen::Vector2i(0);
// Do some more processing
}
So it seems like the error occurs when initializing the Vector2i.
As #MarcGlisse pointed out, Vector2i(0) tells to construct a Vector2i with 0 elements, which will fail at runtime. The reason why fixed sized matrices/vectors constructed with a single scalar interpret this as size rather than value is to allow generic functions, where it is not clear whether the size dynamic or fixed:
template<int SizeAtCompileTime>
void foo(){
Eigen::Matrix<int, SizeAtCompileTime, 1> v(actualSize);
// ...
}
There are two border-cases: Passing two integers to a vector with two elements or passing one integer to a vector with one element, will cause the vector to be initialized with that value(s) if the scalar type of the vector can implicitly constructed from the passed integer type -- otherwise, it will be interpreted as size.
To solve your original problem, there are several alternatives:
Eigen::Vector2i temp1(Eigen::Vector2i::Zero());
Eigen::Vector2i temp2(0,0);
// initialize all elements with a Zero vector:
std::vector<Eigen::Vector2i> currTriangle(3, Eigen::Vector2i::Zero());
currTriangle[0].setZero(); // set 0th element to Zero vector
currTriangle[0].setConstant(0); // equivalent to setZero, but works for arbitrary constants
currTriangle[0].array() = 0; // .array() lets you do element-wise operations
I'm trying to learn Nim by converting different pieces of code, and I've stumbled upon something which I've never seen before.
#include<bits/stdc++.h>
...
for(int t=q&1?u+x:u+x>>1;t>1;)t/=p[++cnt]=sieve[t];
...
sort(p+1,p+cnt+1);
I understand what the ternary operator is and how it works, what I don't quite get is what's going on with the variables "t" and "cnt" (both integers) and the array "p" (an array of integers). How does using an increment as the index of "p" work?
Then there's the sort function, in which I completely gave up because I couldn't find any documentation on what it does (the fact that it's taking an integer added to an array obviously doesn't help).
Lets first start of by making the code a little more readable. A little bit of whitespace never hurt anybody.
for(int t = (q & 1? u + x: u + x >> 1); t > 1;)
{
t /= p[++cnt] = sieve[t];
}
what's going on with the variables "t" and "cnt" (both integers) and the array "p" (an array of integers)
So t is being set to either u + x or u + x >> 1 depending on what q & 1 is. Then inside the loop we are dividing t by whatever the value of sieve at the index of t is. We are also assign that value to the p array at the position of ++cnt. ++cnt is using the pre increment operator to increase the value of cnt by 1 and then using that value for the index of p.
Then there's the sort function, in which I completely gave up because I couldn't find any documentation on what it does
For this I am assuming they are using the std::sort() function. When dealing with arrays the name of the array is treated as a pointer to the first element of the array. So when we see sort(p+1,p+cnt+1); you can translate it to sort(one from the begining of the array, cnt + 1 elements from the begining of the array);. So this is going to sort all of the elements in the array from one from the begining of the array to one less than cnt + 1 elements from the begining of the array.
Are you trying to learn Nim as you said, or trying to learn C? Both things you asked about are pretty basic c:
++cnt has the side effect (cnt=cnt+1) combined with the value that cnt ends up with. That value is used as the index. The side effect is a side effect.
p+1 and p+cnt are each pointers. The name of an array is treated as a constant pointer to the first element of that array in most uses within C. A pointer plus an integer is another pointer, pointing that number of elements past the original.
I would like to create a vector (arma::uvec) of integers - I do not ex ante know the size of the vector. I could not find approptiate function in Armadillo documentation, but moreover I was not successfull with creating the vector by a loop. I think the issue is initializing the vector or in keeping track of its length.
arma::uvec foo(arma::vec x){
arma::uvec vect;
int nn=x.size();
vect(0)=1;
int ind=0;
for (int i=0; i<nn; i++){
if ((x(i)>0)){
ind=ind+1;
vect(ind)=i;
}
}
return vect;
}
The error message is: Error: Mat::operator(): index out of bounds.
I would not want to assign 1 to the first element of the vector, but could live with that if necessary.
PS: I would really like to know how to obtain the vector of unknown length by appending, so that I could use it even in more general cases.
Repeatedly appending elements to a vector is a really bad idea from a performance point of view, as it can cause repeated memory reallocations and copies.
There are two main solutions to that.
Set the size of the vector to the theoretical maximum length of your operation (nn in this case), and then use a loop to set some of the values in the vector. You will need to keep a separate counter for the number of set elements in the vector so far. After the loop, take a subvector of the vector, using the .head() function. The advantage here is that there will be only one copy.
An alternative solution is to use two loops, to reduce memory usage. In the first loop work out the final length of the vector. Then set the size of the vector to the final length. In the second loop set the elements in the vector. Obviously using two loops is less efficient than one loop, but it's likely that this is still going to be much faster than appending.
If you still want to be a lazy coder and inefficiently append elements, use the .insert_rows() function.
As a sidenote, your foo(arma::vec x) is already making an unnecessary copy the input vector. Arguments in C++ are by default passed by value, which basically means C++ will make a copy of x before running your function. To avoid this unnecessary copy, change your function to foo(const arma::vec& x), which means take a constant reference to x. The & is critical here.
In addition to mtall's answer, which i agree with,
for a case in which performance wasn't needed i used this:
void uvec_push(arma::uvec & v, unsigned int value) {
arma::uvec av(1);
av.at(0) = value;
v.insert_rows(v.n_rows, av.row(0));
}
I have a main function which sets up the following variables:
double matrix[numVectors][size] = {
{0.183963, 0.933146, 0.476773, 0.086125, 0.566566, 0.728107, 0.837345, 0.885175, 0.600559, 0.142238},
{0.086523, 0.025236, 0.252289, 0.089437, 0.382081, 0.420934, 0.038498, 0.626125, 0.468158, 0.247754},
{0.969345, 0.127753, 0.736213, 0.264992, 0.518971, 0.216767, 0.390992, 0.242241, 0.516135, 0.990155}
};
double result1[size], result2[size];
double *ptr_matrix = &matrix[0];
double *ptr_result1 = &result1[0];
double *ptr_result2 = &result2[0];
What the above is trying to do is:
Create an array with three rows of 10 doubles
Create two empty arrays of 10 doubles
Create a pointer to the matrix
Create pointers to the two empty arrays
Then, I'm trying to pass all three pointers to another function. This other function will iterate over the matrix rows (only the rows, it doesn't visit the whole matrix space), perform a computation using the row (as an array). The end result is the two empty arrays declared at the beginning end up each becoming one row from the matrix.
Here is the prototype of the second function:
void smallestSum(double (*mat)[size], int num, double *first, double *second)
This function goes through each combination of the matrix rows (0/1, 0/2, 1/2) and checks the sums of their values. The two arrays producing the smallest sum eventually become result1 and result2 from above.
Seeing as this is the first time I'm really delving into pointer/array/matrix territory, I have a few questions:
Am I correctly "getting" a pointer to the matrix? Or do I need to get a pointer to the first value of the matrix instead?
In smallestSum(), can I iterate over the array as I would normally (using for (int i = 0; i < num; i++)?
You need to change the definition of ptr_matrix, as it's not a pointer to a single double, but to the whole row:
double (*ptr_matrix)[size] = &matrix[0];
Then, you can call the function as follows:
smallestSum(ptr_matrix, numVectors, ptr_result1, ptr_result_2);
Inside smallestSum, you can iterate both over rows and over columns.
Note that size must be known at compilation time.
If the function doesn't modify the matrix, consider adding const to the type of its first argument.
The answer abacabadabacaba gave is mostly correct except that size does not need to be known at compile time. If you include size as a parameter to the function you can use it as part of the type for other parameters to that function:
void smallestSum(int size, double (*mat)[size], int num, double *first, double *second)