<div dir="ltr"><div class="markdown-here-wrapper" style=""><blockquote style="margin:1.2em 0px;border-left:4px solid rgb(221,221,221);padding:0px 1em;color:rgb(119,119,119);quotes:none">
<p style="margin:0px 0px 1.2em!important">This means that <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">ndarray</code> needs to know about ufuncs – so instead of a clean layering, we have a circular dependency.</p>
</blockquote>
<p style="margin:0px 0px 1.2em!important">Perhaps we should split ndarray into a <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">base_ndarray</code> class with no arithmetic support (<strong>add</strong>, sum, etc), and then provide an <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">ndarray</code> subclass from umath instead (either the separate extension, or just a different set of files)</p>
<div title="MDH:Jmd0O8KgPHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMzMsIDMzLCAzMyk7Ij5UaGlzIG1lYW5zIHRo
YXQgYG5kYXJyYXlgIG5lZWRzIHRvIGtub3cgYWJvdXQmbmJzcDs8L3NwYW4+PHNwYW4gc3R5bGU9
ImNvbG9yOiByZ2IoMzMsIDMzLCAzMyk7Ij51ZnVuY3Mg4oCTIHNvIGluc3RlYWQgb2YgYSBjbGVh
biBsYXllcmluZywgd2UgaGF2ZSBhIGNpcmN1bGFyJm5ic3A7PC9zcGFuPjxzcGFuIHN0eWxlPSJj
b2xvcjogcmdiKDMzLCAzMywgMzMpOyI+ZGVwZW5kZW5jeS48YnI+PGJyPlBlcmhhcHMgd2Ugc2hv
dWxkIHNwbGl0IG5kYXJyYXkgaW50byBhIGBiYXNlX25kYXJyYXlgIGNsYXNzIHdpdGggbm8gYXJp
dGhtZXRpYyBzdXBwb3J0IChfX2FkZF9fLCBzdW0sIGV0YyksIGFuZCB0aGVuIHByb3ZpZGUgYW4g
YG5kYXJyYXlgIHN1YmNsYXNzIGZyb20gdW1hdGggaW5zdGVhZCAoZWl0aGVyIHRoZSBzZXBhcmF0
ZSBleHRlbnNpb24sIG9yIGp1c3QgYSBkaWZmZXJlbnQgc2V0IG9mIGZpbGVzKTwvc3Bhbj4=" style="height:0;width:0;max-height:0;max-width:0;overflow:hidden;font-size:0em;padding:0;margin:0">​</div></div></div><br><div class="gmail_quote"><div dir="ltr">On Thu, 8 Mar 2018 at 08:25 Nathaniel Smith <<a href="mailto:njs@pobox.com">njs@pobox.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi all,<br>
<br>
Well, this is something that we've discussed for a while and I think<br>
generally has consensus already, but I figured I'd write it down<br>
anyway to make sure.<br>
<br>
There's a rendered version here:<br>
<a href="https://github.com/njsmith/numpy/blob/nep-0015-merge-multiarray-umath/doc/neps/nep-0015-merge-multiarray-umath.rst" rel="noreferrer" target="_blank">https://github.com/njsmith/numpy/blob/nep-0015-merge-multiarray-umath/doc/neps/nep-0015-merge-multiarray-umath.rst</a><br>
<br>
-----<br>
<br>
============================<br>
Merging multiarray and umath<br>
============================<br>
<br>
:Author: Nathaniel J. Smith <<a href="mailto:njs@pobox.com" target="_blank">njs@pobox.com</a>><br>
:Status: Draft<br>
:Type: Standards Track<br>
:Created: 2018-02-22<br>
<br>
<br>
Abstract<br>
--------<br>
<br>
Let's merge ``numpy.core.multiarray`` and ``numpy.core.umath`` into a<br>
single extension module, and deprecate ``np.set_numeric_ops``.<br>
<br>
<br>
Background<br>
----------<br>
<br>
Currently, numpy's core C code is split between two separate extension<br>
modules.<br>
<br>
``numpy.core.multiarray`` is built from<br>
``numpy/core/src/multiarray/*.c``, and contains the core array<br>
functionality (in particular, the ``ndarray`` object).<br>
<br>
``numpy.core.umath`` is built from ``numpy/core/src/umath/*.c``, and<br>
contains the ufunc machinery.<br>
<br>
These two modules each expose their own separate C API, accessed via<br>
``import_multiarray()`` and ``import_umath()`` respectively. The idea<br>
is that they're supposed to be independent modules, with<br>
``multiarray`` as a lower-level layer with ``umath`` built on top. In<br>
practice this has turned out to be problematic.<br>
<br>
First, the layering isn't perfect: when you write ``ndarray +<br>
ndarray``, this invokes ``ndarray.__add__``, which then calls the<br>
ufunc ``np.add``. This means that ``ndarray`` needs to know about<br>
ufuncs – so instead of a clean layering, we have a circular<br>
dependency. To solve this, ``multiarray`` exports a somewhat<br>
terrifying function called ``set_numeric_ops``. The bootstrap<br>
procedure each time you ``import numpy`` is:<br>
<br>
1. ``multiarray`` and its ``ndarray`` object are loaded, but<br>
   arithmetic operations on ndarrays are broken.<br>
<br>
2. ``umath`` is loaded.<br>
<br>
3. ``set_numeric_ops`` is used to monkeypatch all the methods like<br>
   ``ndarray.__add__`` with objects from ``umath``.<br>
<br>
In addition, ``set_numeric_ops`` is exposed as a public API,<br>
``np.set_numeric_ops``.<br>
<br>
Furthermore, even when this layering does work, it ends up distorting<br>
the shape of our public ABI. In recent years, the most common reason<br>
for adding new functions to ``multiarray``\'s "public" ABI is not that<br>
they really need to be public or that we expect other projects to use<br>
them, but rather just that we need to call them from ``umath``. This<br>
is extremely unfortunate, because it makes our public ABI<br>
unnecessarily large, and since we can never remove things from it then<br>
this creates an ongoing maintenance burden. The way C works, you can<br>
have internal API that's visible to everything inside the same<br>
extension module, or you can have a public API that everyone can use;<br>
you can't have an API that's visible to multiple extension modules<br>
inside numpy, but not to external users.<br>
<br>
We've also increasingly been putting utility code into<br>
``numpy/core/src/private/``, which now contains a bunch of files which<br>
are ``#include``\d twice, once into ``multiarray`` and once into<br>
``umath``. This is pretty gross, and is purely a workaround for these<br>
being separate C extensions.<br>
<br>
<br>
Proposed changes<br>
----------------<br>
<br>
This NEP proposes three changes:<br>
<br>
1. We should start building ``numpy/core/src/multiarray/*.c`` and<br>
   ``numpy/core/src/umath/*.c`` together into a single extension<br>
   module.<br>
<br>
2. Instead of ``set_numeric_ops``, we should use some new, private API<br>
   to set up ``ndarray.__add__`` and friends.<br>
<br>
3. We should deprecate, and eventually remove, ``np.set_numeric_ops``.<br>
<br>
<br>
Non-proposed changes<br>
--------------------<br>
<br>
We don't necessarily propose to throw away the distinction between<br>
multiarray/ and umath/ in terms of our source code organization:<br>
internal organization is useful! We just want to build them together<br>
into a single extension module. Of course, this does open the door for<br>
potential future refactorings, which we can then evaluate based on<br>
their merits as they come up.<br>
<br>
It also doesn't propose that we break the public C ABI. We should<br>
continue to provide ``import_multiarray()`` and ``import_umath()``<br>
functions – it's just that now both ABIs will ultimately be loaded<br>
from the same C library. Due to how ``import_multiarray()`` and<br>
``import_umath()`` are written, we'll also still need to have modules<br>
called ``numpy.core.multiarray`` and ``numpy.core.umath``, and they'll<br>
need to continue to export ``_ARRAY_API`` and ``_UFUNC_API`` objects –<br>
but we can make one or both of these modules be tiny shims that simply<br>
re-export the magic API object from where-ever it's actually defined.<br>
(See ``numpy/core/code_generators/generate_{numpy,ufunc}_api.py`` for<br>
details of how these imports work.)<br>
<br>
<br>
Backward compatibility<br>
----------------------<br>
<br>
The only compatibility break is the deprecation of ``np.set_numeric_ops``.<br>
<br>
<br>
Alternatives<br>
------------<br>
<br>
n/a<br>
<br>
<br>
Discussion<br>
----------<br>
<br>
TBD<br>
<br>
<br>
Copyright<br>
---------<br>
<br>
This document has been placed in the public domain.<br>
<br>
<br>
--<br>
Nathaniel J. Smith -- <a href="https://vorpus.org" rel="noreferrer" target="_blank">https://vorpus.org</a><br>
_______________________________________________<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>