set_union issue while using arrays - c++

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

Related

Find max values in a map from key pair first

this is the first time for me to post something, so apologies if the formatting isn't correct or the question is framed incorrectly - I will take any feedback on those elements so I can improve.
I have a map created:
std::map<std::pair<int, int>, int> matchedBoxesCount;
I have populated it and when I iterate over it with:
for(auto it = matchedBoxesCount.cbegin(); it != matchedBoxesCount.cend(); ++it)
{
std::cout << it->first.first << " " << it->first.second << " " << it->second << ",";
}
The result is:
0 0 168, 0 1 8, 0 2 7, 0 3 7, 0 4 1, 0 5 9, 3 0 6, 3 1 41, 3 2 1, 3 3 3, 3 5 4, 3 6 2, 4 0 22, 4 1 1, 4 2 45, 4 3 7, 4 5 3, 4 9 2
I would like to filter this map into a simple map of pairs based on the value field of the key pair.
so based on highest value of each different first.first - so unique firsts 0, 3, 4
0 0 168 - is highest for 0 first field
3 1 41 - is highest for 3 first field
4 2 45 - is highest for 4 first field
copy these into a new map:
std::map<int,int> topScores;
int prevValuefirst = -1;
int currentMax = 0;
for(auto it = matchedBoxesCount.cbegin(); it != matchedBoxesCount.cend(); ++it) {
if (it->first.first == prevValuefirst){
if(it->second > currentMax){
currentMax = it->second;
topScores.at(prevValuefirst) = it->first.second;}
} else {
prevValuefirst = it->first.first;
topScores[prevValuefirst] = it->first.second;
currentMax = it->second;
}
}
it appears to work, but the map isn't sorted prior so this solution would fall over if a 'first.first' element appeared later in the list.
Is there a better way to do this? Should a sort be applied prior to make sure?
Thank you

Matrix manipulation on MATLAB to C++ or OpenCV

I'm trying to do this operation in C++, but I cant wrap my head around it.
I tried looking in http://mathworks.com/help/matlab/ref/image.html but I still don't get it.
im is a matrix in Matlab. Width is 640
im(:,Width+(1:2),:) = im(:,1:2,:);
Is there anything similar to this operation in OpenCV Matrix or C++
Solution 1
You can use colRange function:
mat.colRange(0, 2).copyTo(mat.colRange(w, 2 + w));
Example:
//initilizes data
float data[2][4] = { { 1, 2, 3, 4}, { 5, 6, 7, 8 } };
Mat mat(2, 4, CV_32FC1, &data);
int w = 2; //w is equivelant to Width in your script, in this case I chose it to be 2
std::cout << "mat before: \n" << mat << std::endl;
mat.colRange(0, 2).copyTo(mat.colRange(w, 2 + w));
std::cout << "mat after: \n" << mat << std::endl;
Result:
mat before:
[1, 2, 3, 4;
5, 6, 7, 8]
mat after:
[1, 2, 1, 2;
5, 6, 5, 6]
Solution 2
Alternatively, use cv::Rect object, as follows:
cv::Mat roi = mat(cv::Rect(w, 0, 2, mat.rows));
mat(cv::Rect(0, 0, 2, mat.rows)).copyTo(roi);
There are several way to initialize a Rect, in my case I chose the following c-tor:
cv::Rect(int x, int y, int width, int height);
The result are the same as an in Solution 1.
Maybe you could also use Eigen that can serve the need. It has Block operations
Adapting the example provided under link you would need smth like:
Eigen::MatrixXf m(4, 4);
m << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16;
cout <<"original matrix \n" << m << endl;
m.block<2, 2>(1, 1) = m.block<2, 2>(2, 2);
cout <<"modified matrix \n" << m << endl;
Output:
original matrix
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
modified matrix
1 2 3 4
5 11 12 8
9 15 16 12
13 14 15 16

Weird issue with range based for loop

I am working on learning vectors in my C++ object oriented 1 class and we have been introduced the concept of range based for loops. I decided to practice the range based for-loops separately so that I could get used to the syntax but I came across a weird issue.
#include<iostream>
using namespace std;
int main()
{
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
for ( auto i: a)
{
cout << a[i] << " ";
}
return 0;
}
When I run the above code my output is the following.
2 3 4 5 6 7 8 9 0 1 Press any key to continue...
My output should read
1 2 3 4 5 6 7 8 9 0 Press any key to continue...
Can anyone tell me why my first index is skipped? I have visual studio 2013 professional.
You get the weird output because i in the range loop is the value from the array, not an index. That is,
for (auto i : a)
loops through the values of a. In your code you're effectively printing the sequence a[a[0]], a[a[1]], etc.
The code you probably want is
for (auto i : a) {
std::cout << i << std::endl;
}

Striding windows

Assume that I have a vector:
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
What I need to do is split this vector into block sizes of blocksize with an overlap
blocksize = 4
overlap = 2
The result, would be a 2D vector with size 4 containing 6 values.
x[0] = [1, 3, 5, 7, 9, 11]
x[1] = [ 2 4 6 8 10 12]
....
I have tried to implement this with the following functions:
std::vector<std::vector<double> > stride_windows(std::vector<double> &data, std::size_t
NFFT, std::size_t overlap)
{
std::vector<std::vector<double> > blocks(NFFT);
for(unsigned i=0; (i < data.size()); i++)
{
blocks[i].resize(NFFT+overlap);
for(unsigned j=0; (j < blocks[i].size()); j++)
{
std::cout << data[i*overlap+j] << std::endl;
}
}
}
This is wrong, and, segments.
std::vector<std::vector<double> > frame(std::vector<double> &signal, int N, int M)
{
unsigned int n = signal.size();
unsigned int num_blocks = n / N;
unsigned int maxblockstart = n - N;
unsigned int lastblockstart = maxblockstart - (maxblockstart % M);
unsigned int numbblocks = (lastblockstart)/M + 1;
std::vector<std::vector<double> > blocked(numbblocks);
for(unsigned i=0; (i < numbblocks); i++)
{
blocked[i].resize(N);
for(int j=0; (j < N); j++)
{
blocked[i][j] = signal[i*M+j];
}
}
return blocked;
}
I wrote this function, thinking that it did the above, however, it will just store:
X[0] = 1, 2, 3, 4
x[1] = 3, 4, 5, 6
.....
Could anyone please explain how I would go about modifying the above function to allow for skips by overlap to take place?
This function is similar to this: Rolling window
EDIT:
I have the following vector:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
I want to split this vector, into sub-blocks (thus creating a 2D vector), with an overlap of the parameter overlap so in this case, the parameters would be: size=4 overlap=2, this would then create the following 2D vector:
`block0 = [ 1 3 5 7 9 11]
block1 = [ 2 4 6 8 10 12]
block2 = [ 3 5 7 9 11 13]
block3 = [ 4 6 8 10 12 14]`
So essentially, 4 blocks have been created, each block contains a value where the element is skipped by the overlap
EDIT 2:
This is where I need to get to:
The value of overlap will overlap the results of x in terms of placements inside the vector:
block1 = [1, 3, 5, 7, 9, 11]
Notice from the actual vector block:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
Value: 1 -> This is pushed into block "1"
Value 2 -> This is not pushed into block "1" (overlap is skip 2 places in the vector)
Value 3 -> This is pushed into block "1"
value 4 -> This is not pushed into block "1" (overlap is skip to places in the vector)
value 5 -> This is pushed into block "1"
value 6 -> "This is not pushed into block "1" (overlap is skip 2 places in the vector)
value 7 -> "This value is pushed into block "1"
value 8 -> "This is not pushed into block "1" (overlap is skip 2 places in the vector)"
value 9 -> "This value is pushed into block "1"
value 10 -> This value is not pushed into block "1" (overlap is skip 2 places in the
vector)
value 11 -> This value is pushed into block "1"
BLOCK 2
Overlap = 2;
value 2 - > Pushed back into block "2"
value 4 -> Pushed back into block "2"
value 6, 8, 10 etc..
So each time, the place in the vector is skipped by the "overlap" in this case, it is the value of 2..
This is what the expected output would be:
[[ 1 3 5 7 9 11]
[ 2 4 6 8 10 12]
[ 3 5 7 9 11 13]
[ 4 6 8 10 12 14]]
If I understand you correctly, you're pretty close. You need something like the following. I used int because frankly its easier to type than double =P
#include <iostream>
#include <algorithm>
#include <vector>
#include <limits>
#include <iterator>
std::vector<std::vector<int>>
split(const std::vector<int>& data, size_t blocksize, size_t overlap)
{
// compute maximum block size
std::vector<std::vector<int>> res;
size_t minlen = (data.size() - blocksize)/overlap + 1;
auto start = data.begin();
for (size_t i=0; i<blocksize; ++i)
{
res.emplace_back(std::vector<int>());
std::vector<int>& block = res.back();
auto it = start++;
for (size_t j=0; j<minlen; ++j)
{
block.push_back(*it);
std::advance(it,overlap);
}
}
return res;
}
int main()
{
std::vector<int> data { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
for (size_t i=2; i<6; ++i)
{
for (size_t j=2; j<6; ++j)
{
std::vector<std::vector<int>> blocks = split(data, i, j);
std::cout << "Blocksize = " << i << ", Overlap = " << j << std::endl;
for (auto const& obj : blocks)
{
std::copy(obj.begin(), obj.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
}
std::cout << std::endl;
}
}
return 0;
}
Output
Blocksize = 2, Overlap = 2
1 3 5 7 9 11 13
2 4 6 8 10 12 14
Blocksize = 2, Overlap = 3
1 4 7 10 13
2 5 8 11 14
Blocksize = 2, Overlap = 4
1 5 9 13
2 6 10 14
Blocksize = 2, Overlap = 5
1 6 11
2 7 12
Blocksize = 3, Overlap = 2
1 3 5 7 9 11
2 4 6 8 10 12
3 5 7 9 11 13
Blocksize = 3, Overlap = 3
1 4 7 10
2 5 8 11
3 6 9 12
Blocksize = 3, Overlap = 4
1 5 9
2 6 10
3 7 11
Blocksize = 3, Overlap = 5
1 6 11
2 7 12
3 8 13
Blocksize = 4, Overlap = 2
1 3 5 7 9 11
2 4 6 8 10 12
3 5 7 9 11 13
4 6 8 10 12 14
Blocksize = 4, Overlap = 3
1 4 7 10
2 5 8 11
3 6 9 12
4 7 10 13
Blocksize = 4, Overlap = 4
1 5 9
2 6 10
3 7 11
4 8 12
Blocksize = 4, Overlap = 5
1 6 11
2 7 12
3 8 13
4 9 14
Blocksize = 5, Overlap = 2
1 3 5 7 9
2 4 6 8 10
3 5 7 9 11
4 6 8 10 12
5 7 9 11 13
Blocksize = 5, Overlap = 3
1 4 7 10
2 5 8 11
3 6 9 12
4 7 10 13
5 8 11 14
Blocksize = 5, Overlap = 4
1 5 9
2 6 10
3 7 11
4 8 12
5 9 13
Blocksize = 5, Overlap = 5
1 6
2 7
3 8
4 9
5 10

Regarding vector values

Here is a code snippet below.
Input to program is
dimension d[] = {{4, 6, 7}, {1, 2, 3}, {4, 5, 6}, {10, 12, 32}};
PVecDim vecdim(new VecDim());
for (int i=0;i<sizeof(d)/sizeof(d[0]); ++i) {
vecdim->push_back(&d[i]);
}
getModList(vecdim);
Program:
class dimension;
typedef shared_ptr<vector<dimension*> > PVecDim;
typedef vector<dimension*> VecDim;
typedef vector<dimension*>::iterator VecDimIter;
struct dimension {
int height, width, length;
dimension(int h, int w, int l) : height(h), width(w), length(l) {
}
};
PVecDim getModList(PVecDim inList) {
PVecDim modList(new VecDim());
VecDimIter it;
for(it = inList->begin(); it!=inList->end(); ++it) {
dimension rot1((*it)->length, (*it)->width, (*it)->height);
dimension rot2((*it)->width, (*it)->height, (*it)->length);
cout<<"rot1 "<<rot1.height<<" "<<rot1.length<<" "<<rot1.width<<endl;
cout<<"rot2 "<<rot2.height<<" "<<rot2.length<<" "<<rot2.width<<endl;
modList->push_back(*it);
modList->push_back(&rot1);
modList->push_back(&rot2);
for(int i=0;i < 3;++i) {
cout<<(*modList)[i]->height<<" "<<(*modList)[i]->length<<" "<<(*modList)[i]->width<<" "<<endl;
}
}
return modList;
}
What I see is that the values rot1 and rot2 actually overwrite previous values.
For example that cout statement prints as below for input values defined at top. Can someone tell me why are these values being overwritten?
rot1 7 4 6
rot2 6 7 4
4 7 6
7 4 6
6 7 4
rot1 3 1 2
rot2 2 3 1
4 7 6
3 1 2
2 3 1
You are storing pointers to local variables when you do this kind of thing:
modList->push_back(&rot1);
These get invalidated every loop cycle. You could save yourself a lot of trouble by not storing pointers in the first place.