How to implement __eq__ in shapely (python) - python

I have a question regarding shapely and the usage of == operator. There exists a function to test equality of geometric object: .equals(). However == does not work.
Point((0, 2)).equals(Point((0,2))
returns True.
However:
Point((0, 2)) == Point((0, 2))
returns False
I would like to be able to use the == operator to check if a Point is already present in a list. One use case could be:
if Point not in list_of_points:
list_of_points.append(Point)
As far as I understand, this does not work because == returns False. I know there exists alternative to in by using the any() function, but I would prefer the in keyword:
if not any(Point.equals(point) for point in list_of_points):
list_of_points.append(Point)
Would it be a large effort to implement __eq__ in the shapely/geometry/base.py?
What do you think of this naive implementation of __eq__?
class BaseGeometry(object):
def __eq__(self, other):
return self.equals(other)
or
class BaseGeometry(object):
def __eq__(self, other):
return bool(self.impl['equals'](self, other))

One side effect of implementing __eq__ is that a Point can no longer be a key in a dictionary. If you want that feature, you can add this:
def __hash__(self):
return hash(id(self))

Related

How to implement __hash__ for an object with multiple comparable properties

I have a class called Transaction, which contains multiple attributes. If any of these attributes match, then i want those transactions to be treated as duplicate transactions and hence do not want to store duplicates in a set.
class Transaction:
def __init__(self, a, b):
self.a = a
self.b = b
def __eq__(self, other):
if not isinstance(other, Transaction):
return NotImplemented
return self.a == other.a or self.b == other.b
def __hash__(self):
# TODO
I learnt that it is important to implement both __eq__ as well as __hash__ if we want to avoid duplicates while inserting in a set. Also, if A == B, then their hashes should also match as per the contract.
How can i implement __hash__ in this case, so that if i try to insert a transaction into the set, then it is rejected if it contains repeated value of either attribute 'a' or 'b'.
Thanks in advance!
I'm not sure it's possible to compress an or condition like this into a single hash value. I tried experimenting with applying DeMorgan's law (not nand instead of or) but came up empty.
Your best bet for making the type hashable might just be to return a constant value (such that all instances have the same hash), and rely on the hashtable's collision behavior.
This is implicitly allowed by the standards, because the rule is
a == b implies hash(a) == hash(b)
and not
hash(a) == hash(b) implies a == b
which has never been the case (after all, hash collisions are expected to happen occasionally - a hash is only 32 or 64 bits large)
A set will accommodate for this behavior with its natural collision-avoidance behavior, and while this will not at all be performant, it will at least allow you to use the set data structure in the first place.
>>> class A:
... def __init__(self, prop):
... self.prop = prop
... def __repr__(self):
... return f'A({self.prop})'
... def __eq__(self, other):
... return self.prop == other.prop
... def __hash__(self):
... return 0
...
>>> {A(1), A(2), A(3), A(1)}
{A(1), A(2), A(3)}
Admittedly, this kind of defeats the purpose of using a set, though there might be more point to it if you were using your objects as keys in a dict.
I think it's not possible and you shouldn't do that. Whatever you use in your __eq__ , should also be present in __hash__, otherwise:
let's say you only use hash of a in your __hash__, you would end up with a scenario that two equal objects have different hashes(because their bs are equal) which contradict the actual rule:
if obj1 == obj2 -> True then hash(obj1) == hash(obj2) "must" be True
Same with using only b in __hash__.

functools total_ordering doesn't appear to do anything with inherited class

I am trying sort a list of strings in a way that uses a special comparison. I am trying to use functools.total_ordering, but I'm not sure whether it's filling out the undefined comparisons correctly.
The two I define ( > and ==) work as expected, but < does not. In particular, I print all three and I get that a > b and a < b. How is this possible? I would think that total_ordering would simply define < as not > and not ==. The result of my < test is what you would get with regular str comparison, leading me to believe that total_ordering isn't doing anything.
Perhaps the problem is that I am inheriting str, which already has __lt__ implemented? If so, is there a fix to this issue?
from functools import total_ordering
#total_ordering
class SortableStr(str):
def __gt__(self, other):
return self+other > other+self
#Is this necessary? Or will default to inherited class?
def __eq__(self, other):
return str(self) == str(other)
def main():
a = SortableStr("99")
b = SortableStr("994")
print(a > b)
print(a == b)
print(a < b)
if __name__ == "__main__":
main()
OUTPUT:
True
False
True
You're right that the built-in str comparison operators are interfering with your code. From the docs
Given a class defining one or more rich comparison ordering methods, this class decorator supplies the rest.
So it only supplies the ones not already defined. In your case, the fact that some of them are defined in a parent class is undetectable to total_ordering.
Now, we can dig deeper into the source code and find the exact check
roots = {op for op in _convert if getattr(cls, op, None) is not getattr(object, op, None)}
So it checks if the values are equal to the ones defined in the root object object. We can make that happen
#total_ordering
class SortableStr(str):
__lt__ = object.__lt__
__le__ = object.__le__
__ge__ = object.__ge__
def __gt__(self, other):
return self+other > other+self
#Is this necessary? Or will default to inherited class?
def __eq__(self, other):
return str(self) == str(other)
Now total_ordering will see that __lt__, __le__, and __ge__ are equal to the "original" object values and overwrite them, as desired.
This all being said, I would argue that this is a poor use of inheritance. You're violating Liskov substitution at the very least, in that mixed comparisons between str and SortableStr are going to, to put it lightly, produce counterintuitive results.
My more general recommendation is to favor composition over inheritance and, rather than defining a thing that "is a" specialized string, consider defining a type that "contains" a string and has specialized behavior.
#total_ordering
class SortableStr:
def __init__(self, value):
self.value = value
def __gt__(self, other):
return self.value + other.value > other.value + self.value
def __eq__(self, other):
return self.value == other.value
There, no magic required. Now SortableStr("99") is a valid object that is not a string but exhibits the behavior you want.
Not sure if this is correct, but glancing at the documentation of functools.total_ordering, this stands out to me:
Given a class defining one or more rich comparison ordering methods,
this class decorator supplies the rest.
Emphasis mine. Your class inherits __lt__ from str, so it does not get re-implemented by total_ordering since it isn't missing. That's my best guess.

How to improve my implementation of an arithmetic neutral element (identity) so that it works with numpy.around?

Context
So for a project I was writing some Monte Carlo code and I wanted to support both 2D coordinates and 3D coordinates. The obvious solutions were to implement either 2D and 3D versions of certain functions or to have some 'if' checking in the algorithm itself. I wanted a more elegant solution where I could just work with one algorithm capable of handling both situations. The idea I came up with was to work with some kind of neutral element 'I' for the optional third coordinate (z-direction). It's usage is as follows: if no explicit z value is provided it defaults to I. In any case the z value is effectively used in the calculations but has no effect if z = I.
For example: let a be any number then a + I = I + a = a. Likewise a x I = I x a = a
For addition and multiplication these are I = 0 and respectively I = 1. It is immediately clear that any numerical value for I will not work. For example if I have a cost function of the form xyz + (x +y +x)^2.
Implementation
Luckily, programmatically we are not constrained by mathematics to implement something like that and here's my attempt:
class NeutralElement:
def __add__(self, other):
return other
def __sub__(self, other):
return other
def __mul__(self, other):
return other
def __truediv__(self, other):
return other
def __pow__(self, other):
return self
def __radd__(self, other):
return other
def __rsub__(self, other):
return other
def __rmul__(self, other):
return other
def __rtruediv__(self, other):
return other
def __bool__(self):
return True
def __getitem__(self, index):
return self
def __str__(self):
return 'I'
def __repr__(self):
return 'I'
Usage is simple: n = NeutralElement() and you can then use n in whatever equation you want. The above implementation works well in the sense that the Monte Carlo algorithm finishes without problems and manages to give meaningful results. I can even construct a Numpy array of it and use it. Though it's not compatible with everything. Calling np.around on an array of it gives an error about '_rint' not implemented. Though I did manage to get it to work with round() and ndarray.round(). (Not reflected in the code above.)
Question
My question now is if there's anything I can do to improve compatibility with other functions or just improve this implementation itself. Also welcome are better alternative solutions to the problem described above.
After some feedback I've attempted to narrow down the scope of my question. I would like to modify the above class so that it returns a Numpy array of strings ['I', 'I', ..., 'I'] when numpy.around is used on a Numpy array of NeutralElements

Comparing list of objects to a string

I have a list of objects and I want to compare a string(actually int but I can cast it to str) to check of any of the object in the the list has that string as a member.
Now there is way in which I can iterate over all objects and compare val1 member with my string, but I was wondering if it is possible to do the way below?
class Check:
def __init__(self, val1):
self.val1 = val1
def __str__(self):
return str(self.val1)
o1 = [Check(100)]
test = "100"
for x in o1:
print(x)
print(test in o1)
but the print(test in o1) return false
You may overide the __eq__ operator, in case the other parameter is a string, be nice also to keep a comparison to another Check object
def __eq__(self, other):
if isinstance(other, str):
return other == str(self.val1)
if isinstance(other, Check):
return other.val1 == self.val1
Just because your method returns a string representation which is equal to the string representation of some other object does not make those objects compare equal.
If you wanted instances of your class to be treated as equal to other objects that have the same string representation, then you could add an __eq__ method that implements this:
def __eq__(self, other):
return str(self) == str(other)
You will then find that in your test case that test in o1 evaluates True.
Note that if you do this then Check(100) == Check('100') will also evaluate True (even though their val1 properties are of different types). You do not specifically say whether you want this, but the fact that you want Check(100) == '100' to evaluate True strongly suggests that this is this case.
Full working example with typing.
from typing import List
class Check:
def __init__(self, val1: str or int):
self.val1 = val1
def __str__(self):
return str(self.val1)
def __eq__(self, other):
comparison_type = str
if not isinstance(self.val1, comparison_type):
self.val1 = comparison_type(self.val1)
if not isinstance(other, comparison_type):
other = comparison_type(other)
return self.val1 == other
if __name__ == "__main__":
o1: List[Check] = [Check(100)]
test: str = "100"
print(test in o1)
O1 consists of a list of instances, since you instantiate the Check class, and you're comparing it to a string, which of course won't work. Test is a string object, while the one object o1 contains is, on the other hand, a Check object (that's what type() would return if you ran it on it).
Note that __str__ has nothing to do with turning the object into a string: it's simply used for 'pretty printing' (eg as done by the print function) and is called by print() when ran on the given object, which is contrast to __repr__, which is, conversely, meant for more of a raw, technical, implementation-related display.
Something else needs to be overloaded for the object to support comparisons and in order to define exactly how it should behave in such situations: ie __eq__ and __ne__.

Implementing complex number comparison in Python?

I know that comparison operators with complex numbers can't be defined in general. That is why python throws a TypeError exception when trying to use out-of-the-box complex comparison. I understand why this is the case (please don't go off topic trying to explain why two complex numbers can't be compared).
That said, in this particular case I would like to implement complex number comparison based on their magnitudes. In other words, for z1 and z2 complex values, then z1 > z2 if-and-only-if abs(z1) > abs(z2), where abs() implements complex number magnitude, as in numpy.abs().
I have come up with a solution (at least I think I have) as follows:
import numpy as np
class CustomComplex(complex):
def __lt__(self, other):
return np.abs(self) < np.abs(other)
def __le__(self, other):
return np.abs(self) <= np.abs(other)
def __eq__(self, other):
return np.abs(self) == np.abs(other)
def __ne__(self, other):
return np.abs(self) != np.abs(other)
def __gt__(self, other):
return np.abs(self) > np.abs(other)
def __ge__(self, other):
return np.abs(self) >= np.abs(other)
complex = CustomComplex
This seems to work, but I have a few questions:
Is this the way to go or is there a better alternative?
I would like my package to transparently work with the built-in complex data type as well as numpy.complex. How can this be done elegantly, without code duplication?
I'm afraid I'm going to be off topic (yes I fully read your post :-) ). Ok, Python do allow you to try to compare complex numbers that way because you can define separately all operators even if I strongly advice you not to redefine __eq__ like you did : you are saying 1 == -1 !
IMHO the problem lies there and will spring at your face at one moment (or at the face of anyone who would use your package) : when using equalities and inequalities, ordinary mortals (and most python code) do simple assumptions like -1 != 1, and (a <= b) && (b <= a) implies a == b. And you simply cannot have those 2 assumptions be true at the same time for pure mathematical reasons.
Another classic assumption is a <= b is equivalent to -b <= -a. But with you pre-order a <= b is equivalent to -a <= -b !
That being said, I'll try to answer to your 2 questions :
1: IMHO it is a harmfull way (as dicussed above), but I have no better alternative ...
2: I think a mixin could be an elegant way to limit code duplication
Code example (based on your own code, but not extensively tested):
import numpy as np
class ComplexOrder(Object):
def __lt__(self, other):
return np.absolute(self) < np.absolute(other)
# ... keep want you want (including or not eq and ne)
def __ge__(self, other):
return np.absolute(self) >= np.absolute(other)
class OrderedComplex(ComplexOrder, complex):
def __init__(self, real, imag = 0):
complex.__init__(self, real, imag)
class NPOrderedComplex64(ComplexOrder, np.complex64):
def __init__(self, real = 0):
np.complex64.__init__(self, real)
I'll forgo all the reasons why this may be a bad idea, as per your request.
Is this the way to go or is there a better alternative?
No need to go with numpy, when the normal abs accepts complex numbers and is much faster*. There's also a convenient total_ordering in functools that works well for such simple comparisons, if you want to reduce code (but this may be slower):
from functools import total_ordering
#total_ordering
class CustomComplex(complex):
def __eq__(self, other):
return abs(self) == abs(other)
def __lt__(self, other):
return abs(self) < abs(other)
(That's all the code you need.)
I would like my package to transparently work with the built-in complex data type as well as numpy.complex. How can this be done elegantly, without code duplication?
It automatically works when the right argument is a normal complex (or any) number:
>>> CustomComplex(1+7j) < 2+8j
True
But that's the best you can do, if you want to use the operators < etc. and not functions. The complex type doesn't allow you to set __lt__ and the TypeError is hardcoded.
If you want to do such comparisons on normal complex numbers, you must define and use your own comparison functions instead of the normal operators. Or just use abs(a) < abs(b) which is clear and not terribly verbose.
* Timing built-in abs vs. numpy.abs:
>>> timeit.timeit('abs(7+6j)')
0.10257387161254883
>>> timeit.timeit('np.abs(7+6j)', 'import numpy as np')
1.6638610363006592

Categories