Qt: What's the best way to swap QGraphicsRectItem positions - c++

I'm creating a visualization of sorting algorithms.
I've got a vector of QGraphicsRectItems which are columns with different height and the same width, generated on the app start. They are being shuffled and then added to a QGraphicsScene.
Class named "algorithms" sort a vector of float values which are used to set a height of columns. On swap - it emits a signal to the main class with two integers, so it looks like this:
emit comparison(array[first element to swap], array[second element to swap]);
Function(on_comparison) in the main class is connected with that signal. The problem appeared when I was trying to swap these 2 elements. I've created a variable to set n column position to it. After that I was trying to setPos of columns so I did something like:
void on_comparision(int n, int k)
{
auto nColumnPos = columns[n]->pos().x();
columns[n]->setX(columns[k]->pos().x());
columns[k]->setX(nColumnPos);
}
But it doesn't work. Positions are not changing.
Furthermore
qDebug() <<nColumnPos;
shows value = 0.
I was wondering if my whole program works so I decided to implement 2 sorting algorithms which swap 2 near each other elements and modified on_comparison function to
columns[n]->setX(columns[n].pos().x() + columnsWidth);
columns[n]->setX(columns[n].pos().x() - columnsWidth);
It works but doesn't give a satisfying result. This function will work only with sorting algorithms that swap 2 near each other elements except eg. Bubblesort/cocktailsort.
I was searching for the answer but didn't find anything helpful.
Here's the code:
https://gist.github.com/anonymous/e612e35a7c14eeb650099d4b997f437d

I've managed to solve the problem. The on_comparision function should look like this:
auto nRect = columns[n]->rect();
auto kRect = columns[k]->rect();
auto nColumnPos = nRect.left();
auto kColumnPos = kRect.left();
nRect.moveLeft(kColumnPos);
kRect.moveLeft(nColumnPos);
columns[n]->setRect(nRect);
columns[k]->setRect(kRect);
std::swap(columns[n], columns[k]);
instead of
auto nColumnPos = columns[n]->pos().x();
columns[n]->setX(columns[k]->pos().x());
columns[k]->setX(nColumnPos);
std::swap(columns[n], columns[k]);

Related

What is the best way to get a permutation index list of a given vector

In my application I solve a geometric problem on a given list of points.
0 x0 y0
1 x1 y1
...
The solution file should contain a specific ordering of the points which are represented as a list of their indexes.
1
0
...
After solving the problem I have a result = std::vector<Point>() vector of point objects in a certain order as well as the original list of points as an original = std::vector<Point>() vector. Both vectors naturally have the same size. To generate the output file I go through the result vector and search for the index of the point in the original vector. This is quite inefficient because it does need O(n^2) time. As a slight improvement I do the following:
std::ofstream out(filename);
std::vector<int> indices(instance.size);
std::iota(indices.begin(), indices.end(), 0);
for(auto &point : instance.result.points)
{
for(std::size_t i=0; i<indices.size(); i++)
{
int id = indices[i];
if(point == instance.points[id])
{
out << id << std::endl;
indices.erase(indices.begin()+i);
break;
}
}
}
out.close();
This allows me to not revisit the points that I already found before. Sadly for a 1 million point instance, this process exceeds my time limit and I don't want the export of my solution to take more time than solving the problem itself. Is there a way to efficiently get the indexes of a premutation of some vector in C++? The solution can use a lot of memory if desired.
One of the simple to implement and quite efficient solution is to create a temporary std::unordered_map<Point,size_t> where key is the point and value is position inside original, then do lookup in that map. Details on how to use your (or library provided) data type as a key in std::unordered_map provided here
You can extend the Point structure to contain the original id, besides the position.

openMP slows down when passing from 2 to 4 threads doing binary searches in a custom container

I'm currently having a problem parallelizing a program in c++ using openMP. I am implementing a recommendation system with a user-based collaborative filtering method. To do that, I implemented a sparse_matrix class as a dictionary of dictionaries (where I mean a sort of python dictionary). In my case, since insertion is only done at the beginning of the algorithm when data is read from file, I implemented a dictionary as a std library vector of pair objects (key, value) with a flag that indicates if the vector is sorted. if the vector is sorted, a key is searched using binary searches. otherwise the vector is first sorted and then searched. Alternatively, it is possible to scan the dictionary's entries linearly for example in loops on all the keys of the dictionary. The relevant portion of the code that is causing problems is the following
void compute_predicted_ratings_omp (sparse_matrix &targets,
sparse_matrix &user_item_rating_matrix,
sparse_matrix &similarity_matrix,
int k_neighbors)
{
// Auxiliary private variables
int user, item;
double predicted_rating;
dictionary<int,double> target_vector, item_rating_vector, item_similarity_vector;
#pragma omp parallel shared(targets, user_item_rating_matrix, similarity_matrix)\
private(user, item, predicted_rating, target_vector, item_rating_vector, item_similarity_vector)
{
if (omp_get_thread_num() == 0)
std::cout << " - parallelized on " << omp_get_num_threads() << " threads: " << std::endl;
#pragma omp for schedule(dynamic, 1)
for (size_t iter_row = 0; iter_row < targets.nb_of_rows(); ++iter_row)
{
// Retrieve target user
user = targets.row(iter_row).get_key();
// Retrieve the user rating vector.
item_rating_vector = user_item_rating_matrix[user];
for (size_t iter_col = 0; iter_col < targets.row(iter_row).value().size(); ++iter_col)
{
// Retrieve target item
item = targets.row(iter_row).value().entry(iter_col).get_key();
// retrieve similarity vector associated to the target item
item_similarity_vector = similarity_matrix[item];
// Compute predicted rating
predicted_rating = predict_rating(item_rating_vector,
item_similarity_vector,
k_neighbors);
// Set result in targets
targets.row(iter_row).value().entry(iter_col).set_value(predicted_rating);
}
}
}
}
In this function I compute the predicted rating for a series of target pairs (user, item) (this is simply a weighted average). To do that, I do an outer loop on the target users (which are on the rows of the targets sparse matrix) and I retrieve the rating vector for the current user performing a binary search on the rows of the user_item_rating_matrix. Then, for each column in the current row (i.e. for each item) I retrieve another vector associated to the current item from the sparse matrix similarity_matrix. With these two vectors, I compute the prediction as a weighted average of their elements (on a subset of the items in common between the two vectors).
My problem is the following: I want to parallelize the outer loop using openMP. In the serial version, this functions takes around 3 secs. With openMP on 2 threads, it takes around 2 secs (which it is not bad since I still have some work imbalances in the outerloop). When using 4 threads, it takes 7 secs. I cannot understand what is the cause of this slowdown. Do you have any idea?
I have already thought about the problem and I share my considerations with you:
I access the sparse_matrices only in read mode. Since the matrices
are pre-sorted, all the binary searches should not modify the
matrices and no race-conditions should derive.
Various threads could access to the same vector of the sparse matrix at the same time. I read something about false sharing, but since I do not write in these vectors I think this should not be the reason of the slowdown.
The parallel version seems to work fine with two threads (even if the speedup is lower than expected).
No problem is observed with 4 threads for other choices of the parameters. In particular (cf. "Further details on predict_rating function" below), when I consider all the similar items for the weighted average and I scan the rating vector and search in the similarity vector (the opposite of what I normally do), the execution time scales well on 4 threads.
Further details on predict_rating function: This function works in the following way. The smallest between item_rating_vector and item_similarity_vector is scanned linearly and I do a binary search on the longest of the two. If the rating/similarity is positive, it is considered in the weighted average.
double predict_rating (dictionary<int, double> &item_rating_vector,
dictionary<int, double> &item_similarity_vector)
{
size_t size_item_rating_vector = item_rating_vector.size();
size_t size_item_similarity_vector = item_similarity_vector.size();
if (size_item_rating_vector == 0 || size_item_similarity_vector == 0)
return 0.0;
else
{
double s, r, sum_s = 0.0, sum_sr = 0.0;
int temp_item = 0;
if (size_item_rating_vector < size_item_similarity_vector)
{
// Scan item_rating_vector and search in item_similarity_vector
for (dictionary<int,double>::const_iterator iter = item_rating_vector.begin();
iter != item_rating_vector.end();
++iter)
{
// scan the rating vector forwards: iterate until the whole vector has
// been scanned.
temp_item = (*iter).get_key();
// Retrieve rating that user gave to temp_item (0.0 if not given)
try { s = item_similarity_vector[temp_item]; }
catch (const std::out_of_range &e) { s = 0.0; }
if (s > 0.0)
{
// temp_item is positively similar to the target item. consider it in the average
// Retrieve rating that the user gave to temp_item
r = (*iter).get_value();
// increment the sums
sum_s += s;
sum_sr += s * r;
}
}
}
else
{
// Scan item_similarity_vector and search in item_rating_vector
for (dictionary<int,double>::const_iterator iter = item_similarity_vector.begin();
iter != item_similarity_vector.end();
++iter)
{
// scan the rating vector forwards: iterate until the whole vector has
// been scanned.
temp_item = (*iter).get_key();
s = (*iter).get_value();
if (!(s > 0.0))
continue;
// Retrieve rating that user gave to temp_item (0.0 if not given)
try { r = item_rating_vector[temp_item]; }
catch (const std::out_of_range &e) { r = 0.0; }
if (r > 0.0)
{
// temp_item is positively similar to the target item: increment the sums
sum_s += s;
sum_sr += s * r;
}
}
}
if (sum_s > 0.0)
return sum_sr / sum_s;
else
return 0.0;
}
}
Further details on the hardware: I am running this program on a dell XPS15 with a quad-core i7 processor and 16Gb RAM. I execute the code on a linux virtualbox (I set the VM to use 4 processors and 4Gb RAM).
Thank in advance,
Pierpaolo
It appears you might have a false sharing problem with your targets variable. False sharing is when different threads frequently write to locations near each other (same cache line). By explicitly setting the schedule to dynamic with a chunk size of 1, you are telling OpenMP to only have each thread take tasks one element at a time, thus allowing different threads to work on data that may be near each other in targets.
I would recommend removing the schedule directive just to see how the default scheduler and chunk size do. Then I would try both static and dynamic schedules while varying the chunk size substantially. If your workload or hardware platform is unbalanced, dynamic will probably win, but I would still try static.
Well I found the solution to the problem myself: I post the explanation for the community. In the predict_rating function I used try/catch for handling out_of_range errors thrown by my dictionary structure when a key that is not contained in the dictionary is searched. I read on Are exceptions in C++ really slow that exception handling is computationally heavy in the case an exception is thrown. In my case, for each call of predict_rating I had multiple out_of_range error thrown and handled. I simply removed the try/catch block and wrote a function that searches in the dictionary and return a default value if that key does not exist. This modification produced a speedup of around 2000x and now the program scales well with respect to the number of threads even on the VM.
Thanks to all of you and if you have other suggestions don't hesitate!
Pierpaolo

BFS using adjacency lists in STL

I am trying to write a program for implementing BFS in C++ using STL. I am representing the adjacency list using nested vector where each cell in vector contains a list of nodes connected to a particular vertex.
while(myQ.size()!=0)
{
int j=myQ.front();
myQ.pop();
int len=((sizeof(adjList[j]))/(sizeof(*adjList[j])));
for (int i=0;i<len;i++)
{
if (arr[adjList[j][i]]==0)
{
myQ.push(adjList[j][i]);
arr[adjList[j][i]]=1;
dist(v)=dist(w)+1;
}
}
}
myQ is the queue i am using to keep the nodes along whose edges i will be exploring the graph. In the notation adjList[j] represents the vector pointing to the list and adjList[j][i] represents a particular node in that list. I am storing whether i have explored a particular node by inputting 1 in the array arr. Also dist(v)=dist(w)+1 is not a part of the code but i want to know how i can write it in the correct syntax where my v is the new vertex and w is the old one which discovers v i.e w=myQ.front().
If I have understood your problem, then you want a data structure to store the distances of the graph nodes.
This can be easily done using map.
Use this:
typedef std::map <GraphNode*, int> NodeDist;
NodeDist node_dist;
Replace dist(v)=dist(w)+1; with:
NodeDist::iterator fi = node_dist.find (w);
if (fi == node_dist.end())
{
// Assuming 0 distance of node w.
node_dist[v] = 1;
}
else
{
int w_dist = (*fi).second;
node_dist[v] = w_dist + 1;
}
Please let me if I have misunderstood your problem or the given solution does not work for you. We can work on that.

Iterator and reverse Iterator

I am quiet fresh to C++ and programming in general, I am writing an OpenCv application in C++ environment.
WHAT I AM TRYING TO ACHIEVE:
OK, so I got some Rectangles center points stored in a vector, Now I am using a reverse Iterator to iterate over the vector with rectangle center points and store every 10th center point into new vector.
I then again iterate over that new vector that stores every 10th rectangle center point with normal iterator, And I want to subtract 1st element from 2nd element 3rd element from 4th element and so on, the subtraction results, I want to store into another new vector :D
It might be slightly confusing to some people; I am confused, myself, that is why below I will add the code I have written.
vector<Point> Rightarm;
vector<Point> Leftarm;
vector<Point>::reverse_iterator RightMovmentIter;
vector<Point>::reverse_iterator LeftarmMovmentIter;
vector<Point> RightTracking;
vector<Point> LeftTracking;
for(RightMovmentIter = Rightarm.rbegin(); RightMovmentIter != Rightarm.rend(); RightMovmentIter+=10)
{
RightTracking.push_back(*RightMovmentIter);
}
for(LeftarmMovmentIter = Leftarm.rbegin(); LeftarmMovmentIter != Leftarm.rend(); LeftarmMovmentIter+=10)
{
LeftTracking.push_back(*LeftarmMovmentIter);
}
vector<Point>::iterator RresultIter;
vector<Point>::iterator Leftresult_Iter;
vector<Point> summery;
for(RresultIter = RightTracking.begin(); RresultIter != RightTracking.end(); RresultIter++)
{
summery = *RresultIter - *RresultIter++;
}
PROBLEMS:
1st Problem is that when I run the program I get run time error I belief it's because at the begining of the vector Rightarm & Leftarm do not have 10 elements and when the Iterator runs through it and is trying to look for the 10th element i cant....HOW do I work this out then?
2nd Problem is to do with this line summery = *RresultIter - *RresultIter++; I know it's wrong and this is the best attempt I could of think of, but what I want to do is to subtract 1st element from 2nd element and store it in summery element...
Hopefully This describes my problem well enough for the readers
Regards
As you've correctly noticed, this won't work unless Rightarm.size() is an exact multiple of 10. One way to work around this is to skip elements at the beginning, to make the end line up.
for(RightMovmentIter = Rightarm.rbegin() + Rightarm.size() % 10;
RightMovmentIter != Rightarm.rend();
RightMovmentIter+=10)
As for taking the running difference, there's a standard algorithm for that, std::adjacent_difference.
std::adjacent_difference( RightTracking.begin(), RightTracking.end(),
std::back_inserter( summery ) );
summery.erase( summery.begin() );
This copies the first value without taking a difference (similar to assuming the "before-the-first" value is zero) so the erase() line gets rid of that.

How can I make "real-time" plots with wxMathPlot?

I am thinking of using wxMathPlot for plotting/graphing some data that arrives continuously. I want to draw "Real-time" plot/graph using it. Is that possible?
I.E. I don't want just a static graph of a one-time read of a file - I want the streaming data plotted and continued out to the right of the graph - (and let the left side fall off/scroll out of view)
EDIT
I still have not gotten an answer for this. There is an interesting class in the wxmathPlot library called mpFXYVector but that appears just to draw one plot from a vector of data. What I want is something that can be fed a stream and scroll the graph horizontally (and also resize the scale if needed)
Thanks ravenspoint...!! I did what you said.. It works flawless!
here is my AddData() function:
void mpFXYVector::AddData(float x, float y, std::vector<double> &xs, std::vector<double> &ys)
{
// Check if the data vectora are of the same size
if (xs.size() != ys.size()) {
wxLogError(_("wxMathPlot error: X and Y vector are not of the same length!"));
return;
}
//Delete first point if you need a filo buffer (i dont need it)
//xs.erase(xs.begin());
//xy.erase(xy.begin());
//Add new Data points at the end
xs.push_back(x);
ys.push_back(y);
// Copy the data:
m_xs = xs;
m_ys = ys;
// Update internal variables for the bounding box.
if (xs.size()>0)
{
m_minX = xs[0];
m_maxX = xs[0];
m_minY = ys[0];
m_maxY = ys[0];
std::vector<double>::const_iterator it;
for (it=xs.begin();it!=xs.end();it++)
{
if (*it<m_minX) m_minX=*it;
if (*it>m_maxX) m_maxX=*it;
}
for (it=ys.begin();it!=ys.end();it++)
{
if (*it<m_minY) m_minY=*it;
if (*it>m_maxY) m_maxY=*it;
}
m_minX-=0.5f;
m_minY-=0.5f;
m_maxX+=0.5f;
m_maxY+=0.5f;
}
else
{
m_minX = -1;
m_maxX = 1;
m_minY = -1;
m_maxY = 1;
}
}
in the Main() you only have to:
m_Vector->AddData(xPos,yPos,vectorX, vectorY);
m_plot->Fit();
I think mpFXYVector is the way to go.
The simplest way to deal with this might be to write a wrapper class for mpFXYVector which holds a FIFO buffer of recent data points. Each time a new datapoint arrives, add it to the FIFO buffer, which will drop the oldest point, then load mpFXYVector with the updated buffer. The wxMathPlot class mpWindow will look after the rest of what you need.
A more elegant approach would be a specialization of mpFXYVector which implements the FIFO buffer, using the simple vectors in mpFXYVector. The advantage of this would be that you are holding just one copy of the display data. Unless you are displaying many thousands of points, I doubt the advantage is worth the extra trouble of inheriting from mpFXYVector, rather than simply using the mpFXYVector documented interface.
After looking at the details, the only tricky bit is to replace mpFXYVector::SetData() with a new method Add() to add data points as they arrive. The new method needs to manage the mpFXYVector vectors as FIFO buffers, and to re-implement the code to update the bounding box ( which unfortunately was not written with inheritance in mind ).
The result is that specialization gives a solution with a smaller memory requirement and more flexibility than using a wrapper.
I know this is an old thread but I needed to plot a scrolling X axis with wxMathPlot.
I've done a simple modification to jayjo's code to make X axis scrolling work.
I hoe this helps.
void mpFXYVector::AddData(float x, float y, std::vector<double> &xs, std::vector<double> &ys)
{
// Check if the data vectora are of the same size
if (xs.size() != ys.size()) {
wxLogError(_("wxMathPlot error: X and Y vector are not of the same length!"));
return;
}
//After a certain number of points implement a FIFO buffer
//As plotting too many points can cause missing data
if (x > 300)
{
xs.erase(xs.begin());
ys.erase(ys.begin());
}
//Add new Data points at the end
xs.push_back(x);
ys.push_back(y);
// Copy the data:
m_xs = xs;
m_ys = ys;
// Update internal variables for the bounding box.
if (xs.size()>0)
{
m_minX = xs[0];
m_maxX = xs[0];
m_minY = ys[0];
m_maxY = ys[0];
std::vector<double>::const_iterator it;
for (it=xs.begin();it!=xs.end();it++)
{
if (*it<m_minX) m_minX=*it;
if (*it>m_maxX) m_maxX=*it;
}
for (it=ys.begin();it!=ys.end();it++)
{
if (*it<m_minY) m_minY=*it;
if (*it>m_maxY) m_maxY=*it;
}
m_minX-=0.5f;
m_minY-=0.5f;
m_maxX+=0.5f;
m_maxY+=0.5f;
}
else
{
m_minX = -1;
m_maxX = 1;
m_minY = -1;
m_maxY = 1;
}
}
I do not have any personal experience with wxMathPlot, but I have been working with wxWidgets for years and highly recommend it for cross platform gui programming in c++, with that said according to the wxWiki graphics page the Numerix Graphics Library can be used for real time data so maybe that can help you out. Good luck.
Maybe someone will have same problem and will need it... I needed very fast plotting for showing the data from oscilloscope.
I was getting the data in packets. I made few changes that made a code a lot of faster.
First thing is to change the if state in function SetData from if (xs.size()>0) to if (!xs.empty).
Then you should firstly add all of your data packet to the vector
Vector1_X.push_back(x);
Vector1_Y.push_back(y);
And after that you should fit and set data.
Vector1 ->SetData(Vector1_X,Vector1_Y); // add vectors to main vector
MathPlot1-> Fit(); //fit plot to the data
Vector1_X.clear(); //if you want to clear plot after every packet
Vector1_Y.clear(); //you should use it
Your code in main function will be longer but function will be faster because you add all data "at once".
We ended up using ChartDirector instead. It has a lot of capability and is fast.