qsort and std::sort behaving differently - c++

I am very amazed that sorting via qsort and std::sort can produce different results. I need help explaining the behavior of the following snippets:
using qsort:
// the following comparator has been used in qsort.
// if l<r : -1, l==r : 0 , l>r 1
int cmpre(const void *l, const void *r) {
if ((*(tpl *)l).fhf < (*(tpl *)r).fhf)
return -1;
else
if ((*(tpl *)l).fhf == (*(tpl *)r).fhf) {
if ((*(tpl *)l).nhf == (*(tpl *)r).nhf)
return 0;
else
if ((*(tpl *)l).nhf > (*(tpl *)r).nhf)
return 1;
else
return -1;
} else
return 1;
}
// and sort statement looks like :
qsort(tlst, len, sizeof(tpl), cmpre);
Complete Code link =>
http://ideone.com/zN87tX
Using sort:
// the following comparator was used for sort
int cmpr(const tpl &l, const tpl &r) {
if (l.fhf < r.fhf)
return -1;
else
if (l.fhf == r.fhf) {
if (l.nhf == r.nhf)
return 0;
else
if (l.nhf > r.nhf)
return 1;
else
return -1;
} else
return 1;
}
// and sort statement looks like :
sort(tlst, tlst + len, cmpr);
Complete code link at =>
http://ideone.com/37Dc2S
You can see the output on the link, after and before sorting operation and may wish to check out the compr and compre methods used to compare two tuples. I do not understand why sort is not able to sort the array whereas qsort is able to do so.

Rewrite cmpr() as
bool cmpr(const tpl &l, const tpl &r){
if(l.fhf != r.fhf) return l.fhf < r.fhf;
return l.nhf < r.nhf;
}
Or, you may also reuse cmpre() to implement cmpr().
bool cmpr(const tpl &l, const tpl &r) {
return (cmpre(&l, &r) < 0);
}

Related

Got an Error when using C++20 Polymorphism Lambda Function

I'm trying to write a higher-order function via Lambda in C++, and got this code.
void ProcessList::SortCol(std::string col, bool flag) {
auto CmpGenerator = [&]<typename T>
(std::function<T(const Process &itm)> func) {
return (flag? [&](const Process &a, const Process &b) {
return func(a) < func(b);}
: [&](const Process &a, const Process &b) {
return func(a) > func(b);}
);
};
std::function<bool(const Process &a, const Process &b)> cmp;
if (col == "PID") {
cmp = CmpGenerator([](const Process &itm) {
return itm.GetPid();
});
}
else if (col == "CPU") {
cmp = CmpGenerator([](const Process &itm) {
return itm.GetRatioCPU();
});
}
else if (col == "COMMAND") {
cmp = CmpGenerator([](const Process &itm) {
return itm.GetCmd();
});
}
std::sort(lst.begin(), lst.end(), cmp);
}
However when compiling, g++ reported that no match for call to
no match for call to ‘(ProcessList::SortCol(std::string, bool)::<lambda(std::function<T(const Process&)>)>) (ProcessList::SortCol(std::string, bool)::<lambda(const Process&)>)’
What's wrong here with the code?
The primary problem in this example is that a lambda is not a std::function. See this question.
CmpGenerator deduces its argument as std::function<T(Process const&)>, but a lambda will never match that, so deduction fails.
Furthermore, the body of CmpGenerator tries to return one of two different lambdas - which have different types. Those lambdas are not convertible to each other, so the conditional expression will fail. But we also can't deduce the return type of CmpGenerator since the two different lambdas have different types.
We can start by doing this completely by hand. std::ranges::sort takes a projection, which is very helpful in this regard:
if (col == "PID") {
if (increasing) { // <== 'flag' is not a great name
std::ranges::sort(lst, std::less(), &Process::GetPid);
} else {
std::ranges::sort(lst, std::greater(), &Process::GetPid);
}
} else if (col == "CPU") {
// ...
}
This gives the structure that we need to abstract: we're not generating a comparison object, we're generating a call to sort.
That is:
auto sort_by = [&](auto projection){ // <== NB: auto, not std::function
if (increasing) {
std::ranges::sort(lst, std::less(), projection);
} else {
std::ranges::sort(lst, std::greater(), projection);
}
};
if (col == "PID") {
sort_by(&Process::GetPid);
} else if (col == "CPU") {
sort_by(&Process::GetRatioCPU);
} else if (col == "COMMAND") {
sort_by(&Process::GetCmd);
}

C++ recursive struct comparator

I have created a struct to use as a key in a map to avoid having duplicate elements.
The struct contains pointers to children and siblings of its own type.
For the map, I have created a custom comparator that is supposed to recursively look at the element, the children and the siblings until a difference is found to make sure the elements are the same.
However, for some reason it is not working and Im still getting duplicates. After checking them out in the debugger, I concluded that they are indeed the exact same through and through so the problem must probably be somewhere in there.
This is the struct.
struct controlIdentifier
{
DWORD m_dwID;
DWORD m_dwDefaultID;
DWORD m_dwDisableID;
BYTE m_bType;
int m_nWidth;
int m_nHeight;
int m_nMargineH;
int m_nMargineV;
shared_ptr<controlIdentifier> m_pCHILD;
shared_ptr<controlIdentifier> m_pNEXT;
bool operator<(const controlIdentifier& id) const
{
if (m_dwDefaultID < id.m_dwDefaultID)
return true;
if (m_dwDisableID < id.m_dwDisableID)
return true;
if (m_bType < id.m_bType)
return true;
if (m_nWidth < id.m_nWidth)
return true;
if (m_nHeight < id.m_nHeight)
return true;
if (m_nMargineH < id.m_nMargineH)
return true;
if (m_nMargineV < id.m_nMargineV)
return true;
if (!m_pCHILD && id.m_pCHILD)
return true;
if (m_pCHILD && !id.m_pCHILD)
return false;
if (!m_pNEXT && id.m_pNEXT)
return true;
if (m_pNEXT && !id.m_pNEXT)
return false;
bool smaller = false;
if (m_pCHILD && id.m_pCHILD)
smaller = *m_pCHILD < *id.m_pCHILD;
if (!smaller)
{
if (m_pNEXT && id.m_pNEXT)
return *m_pNEXT < *id.m_pNEXT;
}
else
return smaller;
return false;
}
};
And this is how it's used.
struct cmpBySharedPtr {
bool operator()(const shared_ptr<controlIdentifier>& a, const shared_ptr<controlIdentifier>& b) const {
return *a < *b;
}
};
std::set<FRAMEDESC_SHAREDPTR> m_curFrames;
std::map<shared_ptr<controlIdentifier>, FRAMEDESC_SHAREDPTR, cmpBySharedPtr> m_serialFrames;
for (auto&& frame : m_curFrames)
{
shared_ptr<controlIdentifier> id;
makeIdentifiers(frame, id);
id->m_dwID = newId;
auto find = m_serialFrames.find(id);
if (find == m_serialFrames.end())
{
m_serialFrames.insert(std::pair(id, frame));
newId++;
}
}
m_dwID is not being compared on purspose.
Consider A = (child = 5, next = 6) and B = (child = 6, next = 5). Now A<B is true as (A.child < B.child) is true and it just returns that. Now consider B<A. B.child < A.child is false, so it checks the next fields.. Now B.next < A.next is true, so your comparison returns true.
So this is nonsensical -> A<B is true and B<A is true. This means your comparator is invalid.
The technical term for this is the comparator requires strict weak ordering - see https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings. Your comparator breaks the asymmetry requirement.
You can construct operator < by comparing field by field. But what you did is too little. Basically it shall look like this:
bool operator < (const A& left, const A& right)
{
if (left.firstField < right.firstField) return true;
if (right.firstField < left.firstField) return false; // this case is missing
if (left.secondField < right.secondField) return true;
if (right.secondField < left.secondField) return false; // this case is missing
....
return false;
}
You are missing cases when you can conclude, that for sure, left object is "greater" than right object.

How to represent a mathematical domain in IR?

I would like to define an object representing a mathematical domain from a list of constraints, but I don't have a clear idea on how to do that.
For example, I start from IR and I have the following constraints :
x > 0
x is not in ]3,5]
x is not in [7,12[
Then, my domain is ]0,3] U ]5,7[ U [12,+oo .
How can I nicely store that in a C++ structure ? Have you ever did that before ? Moreover, I want to be able to check easilly if the domain is empty.
Unless you want to use "3rd party" tools like mentioned in the coments, you'll have to write your own Interval class.
To do this, you can do something like this:
class Interval{
struct Range{
bool leftInclusive, rightInclusive;
double left, right;
bool operator<(Range other){return left<other.left;}
}
std::Set<Range> trueRanges;
void addTrueRange(Range r){
//check for overlaps
//merge if overlapping
//otherwise add to trueRanges
}
bool trueAt(double at){
//find the range with the highest left-bound lower than at
auto candidate = truethRanges.upper_bound(at);
if(candidate == trueRanged.end()) return false; // no range found
//on-point checking here
if(at <= candidate->left) return false;
if(at >= candidate->right) return false;
return true;
}
}
The on-point checking is left out here because you cannot simply say doubleOne == doubleTwo because this mitght result in false negatives. So you have to say ABS(doubleOne-doubleTwo) < tinyValue.
For looking for overlaps you can have a look at this.
Answering my own question.
Actually, I followed the idea of sbabbi using a list of intervals coming from boost/numeric/interval, representing the union of intervals.
Here is an example :
typedef boost::numeric::interval_lib::rounded_math<double> RoundedPolicy;
typedef boost::numeric::interval_lib::checking_base<double> CheckingPolicy;
typedef boost::numeric::interval_lib::policies<RoundedPolicy,CheckingPolicy> IntervalPolicies;
typedef boost::numeric::interval<double,IntervalPolicies> interval;
//...
bool is_interval_empty(const interval& inter)
{
return boost::numeric::empty(inter);
}
void restrict(interval& domain, const interval& inter)
{
for(std::list<interval>::iterator it = domain.begin(); it != domain.end(); ++it)
*it = boost::numeric::intersect(*it, inter);
domain.remove_if(is_interval_empty);
}
void restrict(interval& domain, const interval& inter1, const interval& inter2)
{
for(std::list<interval>::iterator it = domain.begin(); it != domain.end(); ++it)
{
domain.push_front(boost::numeric::intersect(*it, inter1));
*it = boost::numeric::intersect(*it, inter2);
}
domain.remove_if(is_interval_empty);
}
//...
std::list<interval> domain;
for(unsigned long int i = 0; i < constraints.size(); ++i)
{
if(constraints[i].is_lower_bound())
{
interval restriction(constraints[i].get_lower_bound(), std::numeric_limits<double>::infinity());
restrict(domain, restriction);
}
else if(constraints[i].is_upper_bound())
{
interval restriction(-std::numeric_limits<double>::infinity(), constraints[i].get_upper_bound());
restrict(domain, restriction);
}
else if(constraints[i].is_forbidden_range())
{
interval restriction1(-std::numeric_limits<double>::infinity(), constraints[i].get_lower_bound());
interval restriction2(constraints[i].get_upper_bound(), std::numeric_limits<double>::infinity());
restrict(domain, restriction1, restriction2);
}
}
if(domain.size() == 0)
std::cout << "empty domain" << std::endl;
else
std::cout << "the domain exists" << std::endl;

How to pass additional array to Thrust's min_element predicate

I'm trying to use Thrust's min_element reduction to find next edge in Prim's algorithm. I iterate over graph edges. This is my comparison function:
struct compareEdge {
__host__ /*__device__*/ bool operator()(Edge l, Edge r) {
if (visited[l.u] != visited[l.v] && visited[r.u] != visited[r.v]) {
return l.cost < r.cost;
} else if (visited[l.u] != visited[l.v]) {
return true;
} else {
return false;
}
}
};
Unfortunately this code cannot run on device, because I use visited array, where I mark already visited nodes. How can I pass this array to my predicate to make it usable from device-executed code?
There are probably a number of ways this can be handled. I will present one approach. Please note that your question is how to pass an arbitrary data set to a functor, which is what I'm trying to show. I'm not trying to address the question of whether or not your proposed functor is a useful comparison predicate for thrust::min_element (which I'm not sure of).
One approach is simply to have a statically defined array:
__device__ int d_visited[DSIZE];
then in your host code, before using the functor, you will need to initialize the array:
cudaMemcpyToSymbol(d_visited, visited, DSIZE*sizeof(int));
Your functor code would have to be modified. Since you may want the functor to be usable either on the host or the device, we will need to control the code based on this:
struct compareEdge {
__host__ __device__ bool operator()(Edge l, Edge r) {
#ifdef __CUDA_ARCH__
if (d_visited[l.u] != d_visited[l.v] && d_visited[r.u] != d_visited[r.v]) {
return l.cost < r.cost;
} else if (d_visited[l.u] != d_visited[l.v]) {
return true;
} else {
return false;
}
#else
if (visited[l.u] != visited[l.v] && visited[r.u] != visited[r.v]) {
return l.cost < r.cost;
} else if (visited[l.u] != visited[l.v]) {
return true;
} else {
return false;
}
#endif
}
};

Error in function sort

I'm trying to use the sort function from STL, but it gives me an error during execution.
My compare function returns true if v is smaller then e:
bool smallerThan(VertexEntry &v, VertexEntry &e) {
if(v.v[0] < e.v[0]) return true;
else if(v.v[1] < e.v[1]) return true;
else if(v.v[2] < e.v[2]) return true;
return false;
}
and here is the call:
sort(vertices.begin(),vertices.end(),smallerThan);
The size of the vector is aprox 400 elements.
Can somebody help me solve my problem?
Thank you!!
Your comparison function is incorrect - it doesn't enforce strict weak ordering.
Use this:
bool smallerThan(VertexEntry const & v, VertexEntry const & e) {
if (v.v[0] < e.v[0])
return true;
else if(v.v[0] > e.v[0])
return false;
else if(v.v[1] < e.v[1])
return true;
else if(v.v[1] > e.v[1])
return false;
else if(v.v[2] < e.v[2])
return true;
return false;
}
Your comparison operator doesn't enforce strict weak ordering. If you're able to use boost one trick I've seen is to bind your object to a boost::tuple and use its strict weak operator<.
If you need to write it yourself, something like this should work:
bool smallerThan(const VertexEntry &v, const VertexEntry &e)
{
if(v.v[0] != e.v[0]) return v.v[0] < e.v[0];
else if(v.v[1] != e.v[1]) return v.v[1] != e.v[1];
else return v.v[2] < e.v[2];
}