Implementing complex number comparison in Python? Implementing complex number comparison in Python? numpy numpy

Implementing complex number comparison in Python?


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 npclass 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_orderingclass 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+8jTrue

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