Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUG: Quantile function on complex numbers doesn't error #22652

Closed
aschaffer opened this issue Nov 22, 2022 · 4 comments
Closed

BUG: Quantile function on complex numbers doesn't error #22652

aschaffer opened this issue Nov 22, 2022 · 4 comments
Labels
00 - Bug component: numpy.lib sprintable Issue fits the time-frame and setting of a sprint

Comments

@aschaffer
Copy link

aschaffer commented Nov 22, 2022

Describe the issue:

Complex numbers are unordered. The complex set, ℂ, is isomorphic with ℝ², which is an unordered vector space. On the other hand, quantiles are the inverse of the cumulative distribution function, CDF. Which is monotonic. It must be, for its inverse to exist.

Consequentially, it makes no mathematical sense to apply quantiles to an unordered set, like a complex input array. Some order can be introduced (e.g., lexicographic) but it is artificial, without a sound mathematical support.

However, both sorting and quantiles functions work in numpy (see example below). Instead, an exception should be thrown.

Reproduce the code example:

import numpy as np

arr_c = np.array([0.5+3.0j, 2.1+0.5j, 1.6+2.3j], dtype=np.dtype('complex128'))
np.quantile(arr_c, 0.5)

Error message:

No response

NumPy/Python version information:

1.23.3 3.8.13 | packaged by conda-forge | (default, Mar 25 2022, 06:04:10)
[GCC 10.3.0]

Context for the issue:

No response

@seberg seberg added component: numpy.lib sprintable Issue fits the time-frame and setting of a sprint labels Nov 22, 2022
@seberg
Copy link
Member

seberg commented Nov 23, 2022

Thanks for the issue. We had a start on deprecating complex sorting, and I think some consensus around the attempt (IIRC, with the idea of providing a way to make complex sort work via an additional by= or so). Or one could maybe flag that the order isn't "proper"...
(See also gh-16700 and issues linked from there. That would directly tie rejecting this to sorting.)

But, I think it makes sense to be pragmatic here and just add an error to quantile for complex results.

@seberg seberg changed the title BUG: Quantile function on complex numbers doesn't throw BUG: Quantile function on complex numbers doesn't error Nov 23, 2022
@aschaffer
Copy link
Author

Sure. Yes, I think we need to stay true to the math. The CDF wrt to real random value variable X, is defined as F_X : ℝ →[0, 1], F_X(x) = P(X ≤ x). Hence, the quantile function, which is the inverse of the CDF, has a real codomain (https://en.wikipedia.org/wiki/Quantile_function).

Now, there is an extension, Z, of random variables from real to complex, making F_Z : ℂ →[0, 1]. But in that case the CDF is defined as a joint distribution probability: F_X(z) = P( Re(Z) ≤ Re(z), Im(Z) ≤ Im(z)). (https://en.wikipedia.org/wiki/Complex_random_variable)

So, that suggests that complex quantile function might be possible, but the induced order is not lexicographic but "joint"; i.e., for z1, z2 ∈ ℂ: z1 < z2 iff (Re(z1) < Re(z2) and Im(z1) < Im(z2)).

But that only induces a partial order (what's the order between (1+2j) and (2+j)...?). But then classical sorting still cannot be used on a partial order, you need topological sort. So things are becoming messy. Certainly not what they are now, wrt ℂ.

@aschaffer
Copy link
Author

aschaffer commented Nov 24, 2022

Actually, things are worse than that: most likely the quantile function for the complex case doesn't even exist.

Consider complex random variable Z = X + Y⋅j with X, Y (real) random variables being independent, which seems the more natural case. Then,

 F_Z(z) = F_X(x)⋅F_Y(y) = P(X≤x)⋅P(Y≤y)

Consider, for example, X,Y as being the scores of 2 separate fair dice. Then,
F_Z(1+6⋅j) = P(X≤1)⋅P(Y≤6) = P(X∈{1})⋅1 = 1/6
F_Z(2+3⋅j) = P(X≤2)⋅P(Y≤3) = P(X∈{1,2})⋅P(Y∈{1,2,3}) = 1/3 ⋅ 1/2 = 1/6

Hence, F(z1) = F(z2) for some z1 ≠ z2; i.e., F_Z(z) is not injective ⇒ not bijective ⇒ not invertible ⇒ quantile function doesn't exist!

MatteoRaso added a commit to MatteoRaso/numpy that referenced this issue Dec 1, 2022
Since percentile is more or less identical to quantile, I also
made it throw an error if it receives a complex input. I also
made nanquantile and nanpercentile throw errors as well.
MatteoRaso added a commit to MatteoRaso/numpy that referenced this issue Dec 1, 2022
Since percentile is more or less identical to quantile, I also
made it throw an error if it receives a complex input. I also made nanquantile and nanpercentile throw errors as well.
MatteoRaso added a commit to MatteoRaso/numpy that referenced this issue Dec 1, 2022
…2652)

Since percentile is more or less identical to quantile, I also made it
throw an error if it receives a complex input. I also made nanquantile
and nanpercentile throw errors as well.
@seberg seberg added sprintable Issue fits the time-frame and setting of a sprint and removed sprintable Issue fits the time-frame and setting of a sprint labels Dec 3, 2022
seberg added a commit that referenced this issue Dec 8, 2022
…#22703)

Since percentile is more or less identical to quantile, I also made it
throw an error if it receives a complex input. I also made nanquantile
and nanpercentile throw errors as well.

* Made the changes recommended by seberg

* Fixed a test for PR 22703

* Fixed tests for quantile

* Shortened some more lines

* Fixup more lines

Co-authored-by: Sebastian Berg <sebastianb@nvidia.com>
@seberg
Copy link
Member

seberg commented Dec 15, 2022

This issue should have been closed, see gh-22703

@seberg seberg closed this as completed Dec 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
00 - Bug component: numpy.lib sprintable Issue fits the time-frame and setting of a sprint
Projects
None yet
Development

No branches or pull requests

2 participants