I try to use GLM vector classes in STL containers. No big deal as long as I don't try to use <algorithm>. Most algorithms rely on the == operator which is not implemented for GLM classes.
Anyone knows an easy way to work around this? Without (re-)implementing STL algorithms :(
GLM is a great math library implementing GLSL functions in c++
Update
I just found out that glm actually implements comparison operators in an extension (here). But how do i use them in stl?
Update 2
This question has been superseded by this one: how to use glm's operator== in stl algorithms?
Many STL algorithms accept a functor for object comparison (of course, you need to exercise special care when comparing two vectors containing floating point values for equality).
Example:
To sort a std::list<glm::vec3> (it's up to you whether sorting vectors that way would make any practical sense), you could use
std::sort(myVec3List.begin(), myVec3List.end(), MyVec3ComparisonFunc)
with
bool MyVec3ComparisonFunc(const glm::vec3 &vecA, const glm::vec3 &vecB)
{
return vecA[0]<vecB[0]
&& vecA[1]<vecB[1]
&& vecA[2]<vecB[2];
}
So, thankfully, there is no need to modify GLM or even reinvent the wheel.
You should be able to implement a operator== as a stand-alone function:
// (Actually more Greg S's code than mine.....)
bool operator==(const glm::vec3 &vecA, const glm::vec3 &vecB)
{
const double epsilion = 0.0001; // choose something apprpriate.
return fabs(vecA[0] -vecB[0]) < epsilion
&& fabs(vecA[1] -vecB[1]) < epsilion
&& fabs(vecA[2] -vecB[2]) < epsilion;
}
James Curran and Greg S have already shown you the two major approaches to solving the problem.
define a functor to be used explicitly in the STL algorithms that need it, or
define the actual operators == and < which STL algorithms use if no functor is specified.
Both solutions are perfectly fine and idiomatic, but a thing to remember when defining operators is that they effectively extend the type. Once you've defined operator< for a glm::vec3, these vectors are extended to define a "less than" relationship, which means that any time someone wants to test if one vector is "less than" another, they'll use your operator. So operators should only be used if they're universally applicable. If this is always the one and only way to define a less than relationship between 3D vectors, go ahead and make it an operator.
The problem is, it probably isn't. We could order vectors in several different ways, and none of them is obviously the "right one". For example, you might order vectors by length. Or by magnitude of the x component specifically, ignoring the y and z ones. Or you could define some relationship using all three components (say, if a.x == b.x, check the y coordinates. If those are equal, check the z coordinates)
There is no obvious way to define whether one vector is "less than" another, so an operator is probably a bad way to go.
For equality, an operator might work better. We do have a single definition of equality for vectors: two vectors are equal if every component is equal.
The only problem here is that the vectors consist of floating point values, and so you may want to do some kind of epsilon comparison so they're equal if all members are nearly equal. But then the you may also want the epsilon to be variable, and that can't be done in operator==, as it only takes two parameters.
Of course, operator== could just use some kind of default epsilon value, and functors could be defined for comparisons with variable epsilons.
There's no clear cut answer on which to prefer. Both techniques are valid. Just pick the one that best fits your needs.
Related
C++20 range algorithms support projections, and obviously like STL algorithms they support custom comparators.
But what I found puzzling is the order of the projection and the comparator.
My "problem"(more of a annoyance, I will quickly learn to use this order of arguments) is that it breaks the left to right flow of code.
Consider the following code (apologies for it not being short, but that is kind of the point, to show that in realistic code order of arguments makes code harder to read when your variables names
are not 2 letter long):
struct PointyPoint {
int x;
int y;
};
struct Item {
std::string name;
PointyPoint location;
};
//...
std::ranges::sort(
items,
[](const PointyPoint &a, const PointyPoint &b) {
return std::tie(a.x, a.y) < std::tie(b.x, b.y);
},
&Item::location);
Issue I have with this code is that I think it would look much nicer if projection was before the lambda (comparator).
Full code godbolt.
Reasons why I can think this order was picked:
STL algorithms have comparator usually as 3rd argument(first after the iterators) so it is to match that
maybe custom comparators are much more common that projection, so to avoid need for supplying that argument
I believe you have already mentioned the reasoning behing this yourself, but let me harden your points:
Porting pre-ranges code to <ranges> should be straightforward. Imagine you have an existing
std::sort(data.begin(), data.end(), std::greater<>{});
and would like to turn that into a <ranges> algorithm call. Imagine you had to go with
std::ranges::sort(data, std::identity{}, std::greater<>{});
This does compose a burden that hinders easy migration. With the actual ordering, you can just change the first version to
std::ranges::sort(data, std::greater<>{});
Using the standard comparison is very low friction, so if you need a projection, it's easy to prepend a std::less<>{}. Admittedly, you could say the same thing about std::identity{}, but that doesn't rule out the first point.
Last, the rational in this document might also be helpful on that subject:
For algorithms that optionally accept functions/predicates (e.g. transform, sort), projection arguments follow functions/predicates. There are no algorithm overloads that allow the user to specify the projection without also specifying a predicate, even if the default would suffice. This is to reduce the number of overloads and also to avoid any potential for ambiguity.
I started writing an oop wrapper for Intels MKL library and came across some design issues. I hope you can help me find the "best" way to handle these issues. The issues are mainly concerning operator overloading and are not critical two the wrapper but effect readability and/or performance.
The first issue is overloading operators considering how the blas functions are defined. As an example, matrix multiplication is defined as
( being matrices, scalars).
Now i can overload , and alone, but for the implementation of BLAS I would need 4 function calls using overloaded operators instead of one. Or i could use a normal function call (which will be implemented anyway), but lose the "natural" way of writing the equation using overloaded operators, making it less readable (but still more readible than with those horrible BLAS names).
The second issue is read and write access to the matrices. As example we can consider the following upper triangular matrix:
This matrix would be stored efficiently in a 1D array like this (order may vary depending on row/column major order):
Since a matrix has two indices, the easiest way to overload reading would be using
<TYPE> & operator() (size_t row, size_t column);
instead of some work around with subscript operators. The problem is handling the zeros. They may not be stored in the array, but mathematically they exist. If I want to read these values in another function (not MKL) I may need to be able to return the zero to handle this (aside from storing the matrix type, which is done for BLAS anyway).
Since () returns a reference, I can't return 0. I could make a dummy variable, but if I were to write to that value, I wouldn't have a upper triangular matrix anymore. So I would have to either change the matrix type, forbid writing to these elements, or ignore it (bad idea).
To change the matrix type I would need to detect writing, that would require explicitly using some kind of proxy object.
To prevent writing, I would probably have to do the same since I can't return a const value because the overload doesn't fit that definition. Alternatively I could forbid writing this way in general, but then I couldn't change the existing matrix itself, which I don't want.
I hope you can give me some pointers on how to handle these issues and what design principles I may be forgetting/should take into account. As I said, they are not critical (I can write appropriate functions for everything instead of operators).
T
I wrote a library for medical image reconstruction https://github.com/kvahed/codeare. The matrix object there has a lot of overloaded operators and convenience function to allow one to write efficiently matlab-like code in c++.
What you want to do for passing the data between MKL and other libraries / algorithms is in my view impossible. How do you want to distinguish 0 from 1e-18. What when you want to go to some numeric optimisation etc. This is premature optimisation that you are looking at. Even if you wanted to use sparsity, you could only do it say column-wise or row-wise, or like above note down, that you have an upper triangular form. But skipping individual 0s. Crazy. Of course copying 0s around doesn't feel right, but getting your algorithms optimised first and then worry about the above would be the way I'd go.
Also don't forget, that a lot of libraries out there cannot handle sparse matrixes, at which point you would have to put in place a recopying of the non-zero part or some bad ass expensive iterator, that would deliver the results.
Btw you would not only need the operator you noted down in your question but also the const variant; in other words:
template <typename T> class Matrix {
...
T& operator()(size_t n, size_t m);
const T& operator()(size_t n, size_t m) const;
...
};
There is so much more expensive stuff to optimise than std::copying stuff. For example SIMD intrinsics ...
https://github.com/kvahed/codeare/blob/master/src/matrix/SIMDTraits.hpp
Herb Sutter, in his proposal for the "spaceship" operator (section 2.2.2, bottom of page 12), says:
Basing everything on <=> and its return type: This model has major advantages, some unique to this proposal compared to previous proposals for C++ and the capabilities of other languages:
[...]
(6) Efficiency, including finally achieving zero-overhead abstraction for comparisons: The vast majority of comparisons are always single-pass. The only exception is generated <= and >= in the case of types that support both partial ordering and equality. For <, single-pass is essential to achieve the zero-overhead principle to avoid repeating equality comparisons, such as for struct Employee { string name; /*more members*/ }; used in struct Outer { Employeee; /*more members*/ }; – today’s comparisons violates zero-overhead abstraction because operator< on Outer performs redundant equality comparisons, because it performs if (e != that.e) return e < that.e; which traverses the equal prefix of
e.name twice (and if the name is equal, traverses the equal prefixes of other members of Employee twice as well), and this cannot be optimized away in general. As Kamiński notes, zero-overhead abstraction is a pillar of C++, and achieving it for comparisons for the first time is a significant advantage of this design based on <=>.
But then he gives this example (section 1.4.5, page 6):
class PersonInFamilyTree { // ...
public:
std::partial_ordering operator<=>(const PersonInFamilyTree& that) const {
if (this->is_the_same_person_as ( that)) return partial_ordering::equivalent;
if (this->is_transitive_child_of( that)) return partial_ordering::less;
if (that. is_transitive_child_of(*this)) return partial_ordering::greater;
return partial_ordering::unordered;
}
// ... other functions, but no other comparisons ...
};
Would define operator>(a,b) as a<=>b > 0 not lead to large overhead? (though in a different form than he discusses). That code would first test for equality, then for less, and finally for greater, rather than only and directly testing for greater.
Am I missing something here?
Would define operator>(a,b) as a<=>b > 0 not lead to large overhead?
It would lead to some overhead. The magnitude of the overhead is relative, though - in situations when costs of running comparisons are negligible in relation to the rest of the program, reducing code duplication by implementing one operator instead of five may be an acceptable trade-off.
However, the proposal does not suggest removing other comparison operators in favor of <=>: if you want to overload other comparison operators, you are free to do it:
Be general: Don’t restrict what is inherent. Don’t arbitrarily restrict a complete set of uses. Avoid special cases and partial features. – For example, this paper supports all seven comparison operators and operations, including adding three-way comparison via <=>. It also supports all five major comparison categories, including partial orders.
For some definition of large. There is overhead because in a partial ordering, a == b iff a <= b and b <= a. The complexity would be the same as a topological sort, O(V+E). Of course, the modern C++ approach is to write safe, clean and readable code and then optimizing. You can choose to implement the spaceship operator first, then specialize once you determine performance bottlenecks.
Generally speaking, overloading <=> makes sense when you're dealing with a type where doing all comparisons at once is either only trivially more expensive or has the same cost as comparing them differently.
With strings, <=> seems more expensive than a straight == test, since you have to subtract each pair of two characters. However, since you already had to load each pair of characters into memory, adding a subtraction on top of that is a trivial expense. Indeed, comparing two numbers for equality is sometimes implemented by compilers as a subtraction and test against zero. And even for compilers that don't do that, the subtract and compare against zero is probably not significantly less efficient.
So for basic types like that, you're more or less fine.
When you're dealing with something like tree ordering, you really need to know up-front which operation you care about. If all you asked for was ==, you really don't want to have to search the rest of the tree just to know that they're unequal.
But personally... I would never implement something like tree ordering with comparison operators to begin with. Why? Because I think that comparisons like that ought to be logically fast operations. Whereas a tree search is such a slow operation that you really don't want to do it by accident or at any time other than when it is absolutely necessary.
Just look at this case. What does it really mean to say that a person in a family tree is "less than" another? It means that one is a child of the other. Wouldn't it be more readable in code to just ask that question directly with is_transitive_child_of?
The more complex your comparison logic is, the less likely it is that what you're doing is really a "comparison". That there's probably some textual description that this "comparison" operation could be called that would be more readable.
Oh sure, such a class could have a function that returns a partial_order representing the relationship between the two objects. But I wouldn't call that function operator<=>.
But in any case, is <=> a zero-overhead abstraction of comparison? No; you can construct cases where it costs significantly more to compute the ordering than it does to detect the specific relation you asked for. But personally if that's the case, there's a good chance that you shouldn't be comparing such types through operators at all.
This question already has answers here:
How can I use std::maps with user-defined types as key?
(8 answers)
Closed 8 years ago.
I'm having quite a hard time trying to debug my little piece of code:
std::map<glm::ivec3,int> myMap;
glm::ivec3 myVec(3, 3, 3);
myMap.find(myVec);
I get the following error:
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.7.1\include\c++\bits\stl_function.h|237|error: no match for 'operator<' in '__x < __y'
Does that mean I can't check whether a glm::ivec3 is smaller than another?
I think that because a stl::map is ordered, the compiler wants to check which pair comes first. I tried to make the key a pointer and it worked.
Isn't there a way to keep the key a value instead of a pointer? This makes me ask another question: how can compare with a greater than operation something that cannot be compared or that is slow to be compared?
Thank you! :)
You can implement a comparison function:
bool operator<(const glm::ivec& lhs, const glm::ivec& rhs)
{
return lhs.x < rhs.x ||
lhs.x == rhs.x && (lhs.y < rhs.y || lhs.y == rhs.y && lhs.z < rhs.z);
}
(change .x, .y, .z to [0], [1], [2] / .first(), .second(), .third() etc as necessary.
how can compare with a greater than operation something that cannot be compared or that is slow to be compared?
Your pointer hack isn't uncommon but isn't always useful and has to be done with care - specifically, if someone comes along to search in the map and wants to find an existing element, they need a pointer to the same existing object that was earlier stored in the map. Or, choose some arbitrary ordering even if it makes no particular sense in the real world - as long as it's consistent.
If a comparison is just slow, you can potentially do things like compare a hash value first then fall back on the slower comparison for rare collisions (or if your hash is long/strong enough, return false on the assumption they're equal).
I'm not familiar with glm, but mathematically this doesn't surprise me as vectors don't have a natural ordering; I.e. What would it mean u < v when the two can be at any location in a 3d space. When you used pointers, it was using address ordering, often isn't a good idea as the addresses have nothing to do with the "values" of the keys. You can't really order on magnitude since you can end up with two completely different vectors being equal. If it is important to have an order you could order them lexicographically, comparing one dimension, then the next, etc. but you might want to consider an unordered_map (a hash table) unless there is some need for an ordering in your problem.
Here is a link that discusses the Java hashCode() function with some discussion of various approaches to hashing for compound objects.
http://www.javamex.com/tutorials/collections/hash_function_guidelines.shtml
For a class that has three ints as it's state, I'd probably do (((x*p)+y)*p)+z where p Is a small prime, say 31. (There are many variations on this and much more complex has functions depending on the structure of the data, etc.)
Here are some more links from SO on C++ hashing.
unordered_map hash function c++
C++ unordered_map using a custom class type as the key
If this has been asked before please forgive me, I could not find it.
I have a custom type for which I can implement (fuzzy) equality but no < operator that is transitive.
The comparison is costly but I have not many elements.
I need to sort out polygons that are alomst identical (they overlap to a large fraction). Since ordering using < is impossible due to the lack of a transitive implementation I am using a std::list like the following:
typedef std::list<Polygon> PolyList;
PolyList purged(rawList);
for (PolyList::iterator iter= purged.begin(); iter!= purged.end(); ++iter) {
for(PolyList::iterator toRemove = find(boost::next(iter),purged.end(),*iter); toRemove != purged.end(); ){
PolyList::iterator next = purged.erase(toRemove);
toRemove = find(next,purged.end(),*iter);
}
}
The complexity is n*n/2 which is unavoidable in my opinion and
while the algorithm works fine, it is still very cumbersome to read and write and I am almost sure there is a standard algorithm for it that I just don't know or at least something as fast but neater to type. As I said sorting is not an option due to the fuzzyness of the data so no unique set or sort.
Many thanks in advance for helping me out
You're probably not going to find an asnwer in the Standard, since your "duplicates" sound like they're not transitive either. That's to say that a==b && b==c does not imply a==c.
For that reason alone, any algorithm has to compare all pairs, which gives you (N*N-1)/2 comparisons (assuming your equality is symmetric, i.e. a==b does imply b==a).
I doubt there is a 'standard algorithm' for achieving what you want, but if you define a distance metric describing the difference between two polygons, then you can select (any) one polygon (call it the base polygon) and sort all the others on the distance from that polygon. Only polygons whose distance from the base are similar may be similar to each other.
Now you only need to consider groups of polygons with similar distances, when deciding which to delete. Without proving it - and I suspect the proof may be involved - I believe this is N log N.