<div dir="ltr"><div dir="ltr"><div dir="ltr">Hi all, <div><br></div><div>   Following up on this. Created a WIP PR </div><div><a href="https://github.com/numpy/numpy/pull/16700">https://github.com/numpy/numpy/pull/16700</a><br></div><div><br></div><div><p style="color:rgb(0,0,0)">As stated in the original thread, We need to start by having a sort() function for complex numbers that can do it based on keys, rather than plain arithmetic ordering.</p><p style="color:rgb(0,0,0)">There are two broad ways to approach a sorting function that supports keys (Not just for complex numbers).</p><ol style="color:rgb(0,0,0)"><li>Add a <code>key</code> kwarg to the <code>sort()</code> (function and method). To support key based sorting on arrays.</li><li>Use a new function on the lines off <code>sortby(c_arr, key=(c_arr.real, c_arr.imag)</code></li></ol><p style="color:rgb(0,0,0)">In this PR I have chosen approach 1 for the following reasons</p><ol style="color:rgb(0,0,0)"><li><p>Approach 1 means it is easier to deal with both in-place method and the function. Since we can make the change in the c-sort function, we have minimal change in the python layer. This I hope results, minimal impact on current code that handles complex sorting. One example within numpy is is <code>linalg</code> module's <code>svd()</code> function.</p></li><li><p>With approach 2 when we deprecate complex arithmetic ordering, existing methods using sort() for complex types, need to update their signature.</p></li></ol><p style="color:rgb(0,0,0)">As it stands the PR does the following 3 things within the Python-C Array method implementation of sort</p><ol style="color:rgb(0,0,0)"><li>Checks for complex type- If array is of complex-type, it creates a default <code>key</code>(When no key is passed) which mimics the current arithmetic ordering in Numpy .</li><li>Uses the keys to perform a <code>Py_LexSort</code> and generate indices.</li><li>We perform the <code>take_along_axis</code> via C call back and copy over the result to the original array (pseudo in-place).</li></ol><p style="color:rgb(0,0,0)">I am requesting feedback/help on implementing <code>take_along_axis</code> logic in C level in an in-place manner and the approach in general.</p><p style="color:rgb(0,0,0)">This will further feed into <code>max()</code> and <code>min()</code> as well. Once we figure this out. Next step would be to deprecate arithmetic ordering for complex types (Which I think will be a PR on it's own)</p><p style="color:rgb(0,0,0)"><br></p><p style="color:rgb(0,0,0)">Regards</p><p style="color:rgb(0,0,0)">Rakesh</p></div></div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Jun 4, 2020 at 9:21 PM Brock Mendel <<a href="mailto:jbrockmendel@gmail.com">jbrockmendel@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">Corresponding pandas issue: <a href="https://github.com/pandas-dev/pandas/issues/28050" target="_blank">https://github.com/pandas-dev/pandas/issues/28050</a></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Jun 4, 2020 at 9:17 PM Rakesh Vasudevan <<a href="mailto:rakesh.nvasudev@gmail.com" target="_blank">rakesh.nvasudev@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><span style="color:rgb(0,0,0);font-family:-webkit-standard;font-size:medium">Hi all,</span><br style="color:rgb(0,0,0)"><br style="color:rgb(0,0,0)"><span style="color:rgb(0,0,0);font-family:-webkit-standard;font-size:medium">As a follow up to </span><a href="https://github.com/numpy/numpy/issues/15981" target="_blank">gh-15981</a><span style="color:rgb(0,0,0);font-family:-webkit-standard;font-size:medium">, I would like to propose a change to bring complex dtype(s) comparison operators and related functions, in line with respective cpython implementations.</span><br style="color:rgb(0,0,0)"><br style="color:rgb(0,0,0)"><span style="color:rgb(0,0,0);font-family:-webkit-standard;font-size:medium">The current state of complex dtype comparisons/ordering as summarised in the issue is as follows:</span><br style="color:rgb(0,0,0)"><br style="color:rgb(0,0,0)"><pre style="color:rgb(0,0,0)"># In python<br><br>>> cnum = 1 + 2j<br>>> cnum_two = 1 + 3j<br><br># Doing a comparision yields<br>>> cnum > cnum_two<br><br>TypeError: '>' not supported between instances of 'complex' and 'complex'<br><br><br># Doing the same in Numpy scalar comparision<br><br>>> np.array(cnum) > np.array(cnum_two)<br><br># Yields<br><br>False<br></pre><br style="color:rgb(0,0,0)"><b style="color:rgb(0,0,0)">NOTE</b><span style="color:rgb(0,0,0);font-family:-webkit-standard;font-size:medium">: only >, <, >= , <= do not work on complex numbers in python , equality (==) does work</span><br style="color:rgb(0,0,0)"><br style="color:rgb(0,0,0)"><span style="color:rgb(0,0,0);font-family:-webkit-standard;font-size:medium">similarly sorting uses comparison operators behind to sort complex values. Again this behavior diverges from the default python behavior.</span><br style="color:rgb(0,0,0)"><br style="color:rgb(0,0,0)"><pre style="color:rgb(0,0,0)"># In native python<br>>> clist = [cnum, cnum_2]<br>>> sorted(clist, key=lambda c: (c.real, c.imag))<br>[(1+2j), (1+3j)]<br><br># In numpy<br><br>>> np.sort(clist) #Uses the default comparision order<br><br># Yields same result<br><br># To get a cpython like sorting call we can do the following in numpy<br>np.take_along_axis(clist, np.lexsort((clist.real, clist.imag), 0), 0)<br></pre><br style="color:rgb(0,0,0)"><span style="color:rgb(0,0,0);font-family:-webkit-standard;font-size:medium">This proposal aims to bring parity between default python handling of complex numbers and handling complex types in numpy</span><br style="color:rgb(0,0,0)"><br style="color:rgb(0,0,0)"><span style="color:rgb(0,0,0);font-family:-webkit-standard;font-size:medium">This is a two-step process</span><br style="color:rgb(0,0,0)"><br style="color:rgb(0,0,0)"><ol style="color:rgb(0,0,0)"><li>Sort complex numbers in a pythonic way , accepting key arguments, and deprecate usage of sort() on complex numbers without key argument</li><ol><li>Possibly extend this to max(), min(), if it makes sense to do so. </li><li>Since sort() is being updated for complex numbers, searchsorted() is also a good candidate for implementing this change.</li></ol><li>Once this is done, we can deprecate the usage of comparison operators (>, <, >= , <=) on complex dtypes</li></ol><br style="color:rgb(0,0,0)"><br style="color:rgb(0,0,0)"><br style="color:rgb(0,0,0)"><b style="color:rgb(0,0,0)">Handling sort() for complex numbers</b><br style="color:rgb(0,0,0)"><span style="color:rgb(0,0,0);font-family:-webkit-standard;font-size:medium">There are two approaches we can take for this </span><br style="color:rgb(0,0,0)"><br style="color:rgb(0,0,0)"><ol style="color:rgb(0,0,0)"><li>update sort() method, to have a ‘key’ kwarg. When key value is passed, use lexsort to get indices and continue sorting of it. We could support lambda function keys like python, but that is likely to be very slow.</li><li>Create a new wrapper function sort_by() (placeholder name, Requesting name suggestions/feedback)That essentially acts like a syntactic sugar for</li><ol><li>np.take_along_axis(clist, np.lexsort((clist.real, clist.imag), 0), 0)</li></ol></ol><ol style="color:rgb(0,0,0)"><li>Improve the existing sort_complex() method with the new key search functionality (Though the change will only reflect for complex dtypes).</li></ol><span style="color:rgb(0,0,0);font-family:-webkit-standard;font-size:medium">We could choose either method, both have pros and cons , approach 1 makes the sort function signature, closer to its python counterpart, while using approach 2 provides a better distinction between the two approaches for sorting. The performance on approach 1 function would vary, due to the key being an optional argument. Would love the community’s thoughts on this.</span><br style="color:rgb(0,0,0)"><br style="color:rgb(0,0,0)"><b style="color:rgb(0,0,0)">Handling min() and max() for complex numbers<br></b><br style="color:rgb(0,0,0)"><br style="color:rgb(0,0,0)"><span style="color:rgb(0,0,0);font-family:-webkit-standard;font-size:medium">Since min and max are essentially a set of comparisons, in python they are not allowed on complex numbers</span><br style="color:rgb(0,0,0)"><pre style="color:rgb(0,0,0)">>> clist = [cnum, cnum_2]<br>>>> min(clist)<br>Traceback (most recent call last):<br>  File "<stdin>", line 1, in <module><br>TypeError: '<' not supported between instances of 'complex' and 'complex'<br><br># But using keys argument again works<br>min(clist, key=lambda c: (c.real, c.imag))</pre><span style="color:rgb(0,0,0);font-family:-webkit-standard;font-size:medium">We could use a similar key kwarg for min() and max() in python, but question remains how we handle the keys, in this use case , naive way would be to sort() on keys and take last or first element, which is likely going to be slow. Requesting suggestions on approaching this.</span><br style="color:rgb(0,0,0)"><br style="color:rgb(0,0,0)"><b style="color:rgb(0,0,0)">Comments on isclose()</b><br style="color:rgb(0,0,0)"><span style="color:rgb(0,0,0);font-family:-webkit-standard;font-size:medium">Both python and numpy use the absolute value/magnitude for comparing if two values are close enough. Hence I do not see this change affecting this function.</span><br style="color:rgb(0,0,0)"></div><div dir="ltr"><span style="color:rgb(0,0,0);font-family:-webkit-standard;font-size:medium"><br></span></div><div><font color="#000000" face="-webkit-standard" size="3"><span>Requesting feedback and suggestions on the above.</span></font></div><div><font color="#000000" face="-webkit-standard" size="3"><span><br></span></font></div><div><font color="#000000" face="-webkit-standard" size="3"><span>Thank you,</span></font></div><div><font color="#000000" face="-webkit-standard" size="3"><span><br></span></font></div><div><font color="#000000" face="-webkit-standard" size="3"><span>Rakesh</span></font></div></div>
_______________________________________________<br>
NumPy-Discussion mailing list<br>
<a href="mailto:NumPy-Discussion@python.org" target="_blank">NumPy-Discussion@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/numpy-discussion</a><br>
</blockquote></div>
_______________________________________________<br>
NumPy-Discussion mailing list<br>
<a href="mailto:NumPy-Discussion@python.org" target="_blank">NumPy-Discussion@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/numpy-discussion</a><br>
</blockquote></div>