Related
I have an object of std::vector<std::array<double, 16>>
vector entry Data
[0] - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[1] - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[2] - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[...] - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
This is intended to represent a 4x4 matrix in ravel format.
To not duplicate information I would like to create a pointer to extract a 3x3 from the above structure:
I have mathematical operations for the 3x3 structure (std::array<double, 9>)
someStructure: pointing to data elements [0, 1, 2, 4, 5, 6, 8, 9 10]
The end goal is do: std::array<double, 9> tst = someStructure[0] + someStructure[1];
Is this doable?
Best Regards
The 3x3 part is not contiguous, hence a pointer alone wont help here.
You can write a view_as_3x3 that allows you to access elements of the submatrix of the 4x4 as if it was contiguous:
struct view_as_3x3 {
double& operator[](size_t index) {
static const size_t mapping[] = {0, 1, 2, 4, 5, 6, 8, 9, 10};
return parent[mapping[index]];
}
std::array<double, 16>& parent;
};
Such that for example
for (size_t = 0; i< 9; ++i) std::cout << " " << view_as_3x3{orignal_matrix}[i];
is printing the 9 elements of the 3x3 sub-matrix of the original 4x4 original_matrix.
Then you could more easily apply your 3x3 algorithms to the 3x3 submatrix of a 4x4 matrix. You just need to replace the std::array<double, 9> with some generic T. For example change
double sum_of_elements(const std::array<double, 9>& arr) {
double res = 0;
for (int i=0;i <9; ++i) res += arr[i];
return res;
}
To:
template <typename T>
double sum_of_elements(const T& arr) {
double res = 0;
for (int i=0;i <9; ++i) res += arr[i];
return res;
}
The calls are then
std::array<double, 16> matrix4x4;
sum_of_elements(view_as_3x3{matrix4x4});
// or
std::array<double, 9> matrix3x3;
sum_of_elements(matrix3x3);
It would be nicer to use iterators instead of indices, however, writing the view with custom iterators requires considerable amount of boilerplate. On the other hand, I would not suggest to use naked std::arrays in the first place, but rather some my_4x4matrix that holds the array as member and provides iterators and more convenience methods.
Suppose I have a following 2D matrix in the following format. First line indicates the dimension and the rest other lines contains the elements. In this case it's a 6*6 Matrix:
6
1 2 3 4 2 3
3 3 4 5 2 1
4 3 3 1 2 3
5 4 3 6 2 1
3 2 4 3 4 3
2 3 4 1 5 6
Normally we can store the matrix in a vector using this:
typedef std::vector<int32_t> vec_1d;
typedef std::vector<vec_1d> vec_2d;
vec_2d array{
{ 1, 2, 3, 4, 2, 3 }
, { 3, 3, 4, 5, 2, 1 }
, { 4, 3, 3, 1, 2, 3 }
, { 5, 4, 3, 6, 2, 1 }
, { 3, 2, 4, 3, 4, 3 }
, { 2, 3, 4, 1, 5, 6 }
};
But if I want to take this array in the format I have shown above from a text file into a 2d vector like the above one, how will I do this in c++ ?
This should work:
#include "fstream"
#include "vector"
using namespace std;
int main()
{
ifstream fin("file.txt");
int n;
fin >> n;
vector < vector <int> > matrix (n, vector <int>(n));
// or vec_2d matrix (n, vec_1d(n)); with your typedefs
for (auto &i: matrix)
for (auto &j: i)
fin >> j;
}
I am trying to get union of 4 arrays using set_union. Here is the code I have so far:
int setA[5] = {2, 4, 5, 7, 8};
int setB[7] = {1, 2, 3, 4, 5, 6, 7};
int setC[5] = {2, 5, 8, 8, 15};
int setD[6] = {1, 4, 4, 6, 7, 12};
int AunionB[12];
int CunionD[11];
int finalUnion[23];
int *lastAunionB;
int *lastCunionD;
ostream_iterator<int> screen(cout, " ");
lastAunionB = set_union(setA, setA+5, setB, setB+7, AunionB);
cout << "AunionB = ";
copy(AunionB, lastAunionB, screen);
cout << endl;
lastCunionD = set_union(setC, setC+5, setD, setD+6, CunionD);
cout << "CunionD = ";
copy(CunionD, lastCunionD, screen);
cout << endl;
set_union(AunionB, AunionB+12, CunionD, CunionD+11, finalUnion);
cout << "Final Union = ";
copy(finalUnion, finalUnion+23, screen);
cout << endl;
When I ran the code, I got the following output:
AunionB = 1 2 3 4 5 6 7 8
CunionD = 1 2 4 4 5 6 7 8 8 12 15
Final Union = 1 2 3 4 5 6 7 2 4 4 5 6 7 8 8 12 15 52187240 1 1863041424 32767 0 0
Therefore, the unions of setA and setB works as intended as does the union of setC and setD. However, when I try to get the union of all for sets, it doesn't work! I'm guessing the last 5 values of finalUnion are the address fields but how do I remove them? Also, the union itself is incorrect and I can't understand why.
The size of the AunionB and Cuniond is not 12 and 11 because:
Elements from the second range that have an equivalent element in the first range are not copied to the resulting range.
Try this code:
int setA[5] = { 2, 4, 5, 7, 8 };
int setB[7] = { 1, 2, 3, 4, 5, 6, 7 };
int setC[5] = { 2, 5, 8, 8, 15 };
int setD[6] = { 1, 4, 4, 6, 7, 12 };
int AunionB[12];
int CunionD[11];
int finalUnion[23];
int *lastAunionB;
int *lastCunionD;
ostream_iterator<int> screen(cout, " ");
lastAunionB = set_union(setA, setA + 5, setB, setB + 7, AunionB);
cout << "AunionB = ";
copy(AunionB, lastAunionB, screen);
cout << endl;
lastCunionD = set_union(setC, setC + 5, setD, setD + 6, CunionD);
cout << "CunionD = ";
copy(CunionD, lastCunionD, screen);
cout << endl;
int *finalUnionEnd;
finalUnionEnd = set_union(AunionB, lastAunionB, CunionD, lastCunionD, finalUnion);
cout << "Final Union = ";
copy(finalUnion, finalUnionEnd, screen);
cout << endl;
And then you got the right result:
Final Union = 1 2 3 4 4 5 6 7 8 8 12 15
A Union operation removes values that the two sets have in common.
Note that AUnionB has 8 elements (not the 12 that your code predicts).
You need to adjust your union-of-union code to account for the actual size of the two initial unions. You have everything prepared to do it correctly:
int *lastFinalUnion = set_union(AunionB, lastAunionB, CunionD, lastCunionD, finalUnion);
Note that set C has two distinct occurrences of 8 and set D has two distinct occurrences of 4, which is why they appear duplicated in the intermediate result.
UPDATE
Also, I tried your code and i'm getting the answer as 1 2 3 4 5 6 7 2 4 4 5 6 7 8 8 12 15 . Shouldn't the answer be 1 2 3 4 4 5 6 7 8 8 12 15
I believe you are correct, but I'm not in front of a C++ compiler to step through and see what's doing on, or to verify your output. The actual code was edited in by another SO member, but it looks correct to me.
In the simplest case, set_union performs the "union" operation from set theory: the output range contains a copy of every element that is contained in [first1, last1), [first2, last2), or both. The general case is more complicated, because the input ranges may contain duplicate elements. The generalization is that if a value appears m times in [first1, last1) and n times in [first2, last2) (where m or n may be zero), then it appears max(m,n) times in the output range.
https://www.sgi.com/tech/stl/set_union.html
I'm trying to use the MKL routine mkl_dcsradd to add an upper-triangular matrix to its transpose. In this case, the upper triangular matrix stores part of the adjacency matrix of a graph, and I need the full version for implementing another algorithm.
In this simplified example, I start with a list of (11) edges, and build an upper-triangular CSR matrix from it. I have checked that this much works. However, when I try to add it to its transpose, dcsradd stops on the final row, saying it's run out of space. However, this shouldn't be the case. An upper triangular matrix (no zeros along the diagonal) with n non-zero entries, when added to its transpose, should result in a matrix with 2n (22) non-zeros.
When I supply dcsradd with a maximum non-zeros of 22, it fails, but when I supply it with 23 (an excessive value), it works correctly. Why is this?
I've simplified my code down to a minimal example demonstrating the error:
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <mkl.h>
int main()
{
int nnz = 11;
int numVertices = 10;
int32_t u[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1 };
int32_t v[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 5, 8 };
double w[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
int fullNnz = nnz * 2;
int dim = numVertices;
double triData[nnz];
int triCols[nnz];
int triRows[dim];
// COO to upper-triangular CSR
int info = -1;
int job [] = { 2, 1, 0, 0, nnz, 0 };
mkl_dcsrcoo(job, &dim,
triData, triCols, triRows,
&nnz, w, u, v,
&info);
printf("info = %d\n", info);
// Allocate final memory
double data[fullNnz];
int cols[fullNnz];
int rows[dim];
// B = A + A^T (to make a full adjacency matrix)
int request = 0, sort = 0;
double beta = 1.0;
int WRONG_NNZ = fullNnz + 1; // What is happening here?
mkl_dcsradd("t", &request, &sort, &dim, &dim,
triData, triCols, triRows,
&beta, triData, triCols, triRows,
data, cols, rows,
&WRONG_NNZ, &info);
printf("info = %d\n", info);
// Convert back to 0-based indexing (via Cilk)
cols[:]--;
rows[:]--;
printf("data:");
for (double d : data) printf("%.0f ", d);
printf("\ncols:");
for (int c : cols) printf("%d ", c);
printf("\nrows:");
for (int r : rows) printf("%d ", r);
printf("\n");
return 0;
}
I compile with:
icc -O3 -std=c++11 -xHost main.cpp -o main -openmp -L/opt/intel/composerxe/mkl/lib -lmkl_intel_lp64 -lmkl_core -lmkl_intel_thread -lpthread -lm
When I give 22, the output is:
info = 0
info = 10
data:1 10 1 2 11 2 3 3 4 4 5 10 5 6 6 7 7 8 11 8 9 0
cols:1 5 0 2 8 1 3 2 4 3 5 0 4 6 5 7 6 8 1 7 9 -1
rows:0 2 5 7 9 11 14 16 18 21
But, when I give 23, the output is:
info = 0
info = 0
data:1 10 1 2 11 2 3 3 4 4 5 10 5 6 6 7 7 8 11 8 9 9
cols:1 5 0 2 8 1 3 2 4 3 5 0 4 6 5 7 6 8 1 7 9 8
rows:0 2 5 7 9 11 14 16 18 21
I want to loop an array then during each loop I want to loop backwards over the previous 5 elements.
So given this array
int arr[24]={3, 1, 4, 1, 7, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4}
and this nested loop
for(int i=0;i<arr.size;i++)
{
for(int h=i-5; h<i; h++)
{
//things happen
}
}
So, if i=0, second loop would loop last few elements 4,6,2,6,5.
How could you handle this?
I'm assuming that:
You only want to go over previous values (i.e. no wrap around) You
You don't actually want arr to be a multi-dimensional array as suggested
by your choice of tags
You want to include the current i in your five values
This is just a small modification to your code that will do (what I think) you are asking:
#include <math>
int main()
{
int arr[24]={3, 1, 4, 1, 7, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4}
for(int i=0;i<arr.size;i++)
{
for(int h = max(i-4, 0); h < i+1; h++)
{
//things happen
}
}
}
note the h = max(i-4, 0) and h < i+1This will reduce the number of iterations of the inner loop so that it starts from index 0 and loops up through the five values up to and including i. (four values and i). h will always be within bounds.
The case where i==arr.size won't be a problem in the inner loop as the outer loop will terminate before that happens (i is always within bounds).
Edit: I saw this comment:
I want the first element to consider the last final 5 elements of the array though.
in which case, your loops should look like:
for(int i=0;i<arr.size;i++)
{
for(int h=0; h<5; h++)
{
int index = (i + arr.size - h) % arr.size;
//things happen
//access array with arr[index];
}
}
This should do what you want:
When i=0, h=0 index=(0+24-0)%24 which is 0. For h=1 we go one less, index=(0+24-1)%24 = 23 and so on for the next values of h.
The code gets the last 5 values, wrapping round, inclusive of the current value. (so will get 20,21,22,23,0 when i=0, 21,22,23,0,1 when i=1)
If you want the five before, non-inclusive, then inner loop should be:
for(int h=1; h<=5; h++)
here is the current output of the loop as it stands:
i 0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 ... 22 22 22 22 22 23 23 23 23 23
h 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 ... 0 1 2 3 4 0 1 2 3 4
index 0 23 22 21 20 1 0 23 22 21 2 1 0 23 22 3 2 1 0 23 ... 22 21 20 19 18 23 22 21 20 19
I assume you want it to loop around (don't know why). if so, use modulo:
int index = (h + arr.size) % arr.size;
Using the modulo operator.
for (int i = 0; i < arr.size; i++)
{
for (int h = 5; h > 0; h--)
{
const int array_length = sizeof(arr) / sizeof(arr[0]);
int index = (i - h + array_length) % array_length; // Use 'sizeof(arr) / sizeof(arr[0])' to get the size of the array
//things happen
}
}
Is using if statement not an option?
const int array_size = 24;
int arr[array_size] = { 1,3,4,5,...,2 }
for(int i=0;i<array_size;i++)
{
for(int h=i-5; h<i; h++)
{
int arr_index = (h >= 0) ? h : (array_size + h);
//do your things with arr[arr_index]
}
}
you may also start the nested loop with something like:
for(int h=i-min(i,5);h<i;++h)
{
}
which let you process first 5 cells as well. also, if you are dealing with some kind of signal or image processing consider extending arr to have 29 elements with preceding 5 zeros or whatever value would be suitable, and start the first for-loop with 5th element.
Just make an if statement in nested loop. Something like this
for( int h = i-5; h < i; h++ )
{
// do stuff
if( i == 0 )
break;
}