Skip to content

Commit

Permalink
MAINT: Update vendored uarray version
Browse files Browse the repository at this point in the history
The also moves the compile flag detection code from fft._pocketfft into
_build_utils as it is now needed to build uarray as well.
  • Loading branch information
peterbell10 committed Jul 9, 2019
1 parent 6a3afbc commit 27c0be4
Show file tree
Hide file tree
Showing 6 changed files with 1,288 additions and 236 deletions.
55 changes: 55 additions & 0 deletions scipy/_build_utils/compiler_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""
Helpers for detection of compiler features
"""
import tempfile
import os

def try_compile(compiler, code=None, flags=[], ext=None):
"""Returns True if the compiler is able to compile the given code"""
from distutils.errors import CompileError

code = code or 'int main (int argc, char **argv) { return 0; }'
ext = ext or compiler.src_extensions[0]

with tempfile.TemporaryDirectory() as temp_dir:
fname = os.path.join(temp_dir, 'main'+ext)
with open(fname, 'w') as f:
f.write(code)

try:
compiler.compile([fname], extra_postargs=flags)
except CompileError:
return False
return True


def has_flag(compiler, flag, ext=None):
"""Returns True if the compiler supports the given flag"""
return try_compile(compiler, flags=[flag], ext=ext)


def get_cxx_std_flag(compiler):
"""Detects compiler flag for c++14, c++11 or None if not detected"""
gnu_flags = ['--std=c++14', '--std=c++11']
flags_by_cc = {
'msvc': ['/std:c++14', None],
'intelw': ['/Qstd=c++14', '/Qstd=c++11']
}
flags = flags_by_cc.get(compiler.compiler_type, gnu_flags)

for flag in flags:
if flag is None:
return None

if has_flag(compiler, flag):
return flag

from numpy.distutils import log
log.warn('Could not detect c++ standard flag')
return None


def try_add_flag(args, compiler, flag, ext=None):
"""Appends flag to the list of arguments if supported by the compiler"""
if try_compile(compiler, flags=args+[flag], ext=ext):
args.append(flag)
26 changes: 25 additions & 1 deletion scipy/_lib/uarray/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,28 @@
If you are looking for overrides for NumPy-specific methods, see the
documentation for :obj:`unumpy`. This page explains how to write
back-ends and multimethods.
``uarray`` is built around a back-end protocol, and overridable multimethods.
It is necessary to define multimethods for back-ends to be able to override them.
See the documentation of :obj:`generate_multimethod` on how to write multimethods.
Let's start with the simplest:
``__ua_domain__`` defines the back-end *domain*. The domain consists of a string
that, by convention, is the module for which a back-end is provided, along with
related packages in the ecosystem. For example, the ``"numpy"`` domain may cover
backends for NumPy itself, as well as SciPy and the numerical scikit packages.
For the purpose of this demonstration, we'll be creating an object and setting
its attributes directly. However, note that you can use a module or your own type
as a backend as well.
>>> class Backend: pass
>>> be = Backend()
>>> be.__ua_domain__ = "ua_examples"
It might be useful at this point to sidetrack to the documentation of
:obj:`generate_multimethod` to find out how to generate a multimethod
overridable by :obj:`uarray`. Needless to say, writing a backend and
Expand All @@ -25,7 +33,9 @@
is certainly helpful. We expect core API designers/specifiers to write the
multimethods, and implementors to override them. But, as is often the case,
similar people write both.
Without further ado, here's an example multimethTrueod:
>>> import uarray as ua
>>> def override_me(a, b):
... return Dispatchable(a, int),
Expand All @@ -34,19 +44,23 @@
>>> overridden_me = ua.generate_multimethod(
... override_me, override_replacer, "ua_examples"
... )
Next comes the part about overriding the multimethod. This requires
the ``__ua_function__`` protocol, and the ``__ua_convert__``
protocol. The ``__ua_function__`` protocol has the signature
``(method, args, kwargs)`` where ``method`` is the passed
multimethod, ``args``/``kwargs`` specify the arguments and ``dispatchables``
is the list of converted dispatchables passed in.
>>> def __ua_function__(method, args, kwargs):
... return method.__name__, args, kwargs
>>> be.__ua_function__ = __ua_function__
The other protocol of interest is the ``__ua_convert__`` protocol. It has the
signature ``(dispatchables, coerce)``. When ``coerce`` is ``False``, conversion
between the formats should ideally be an ``O(1)`` operation, but it means that
no memory copying should be involved, only views of the existing data.
>>> def __ua_convert__(dispatchables, coerce):
... for d in dispatchables:
... if d.type is int:
Expand All @@ -55,35 +69,45 @@
... else:
... yield d.value
>>> be.__ua_convert__ = __ua_convert__
Now that we have defined the backend, the next thing to do is to call the multimethod.
>>> with ua.set_backend(be):
... overridden_me(1, "2")
('override_me', (1, '2'), {})
Note that the marked type has no effect on the actual type of the passed object.
We can also coerce the type of the input.
>>> with ua.set_backend(be, coerce=True):
... overridden_me(1, "2")
... overridden_me(1.0, "2")
('override_me', ('1', '2'), {})
('override_me', ('1.0', '2'), {})
Another feature is that if you remove ``__ua_convert__``, the arguments are not
converted at all and it's up to the backend to handle that.
>>> del be.__ua_convert__
>>> with ua.set_backend(be):
... overridden_me(1, "2")
('override_me', (1, '2'), {})
You also have the option to return ``NotImplemented``, in which case processing moves on
to the next back-end, which in this case, doesn't exist. The same applies to
``__ua_convert__``.
>>> be.__ua_function__ = lambda *a, **kw: NotImplemented
>>> with ua.set_backend(be):
... overridden_me(1, "2")
Traceback (most recent call last):
...
uarray.backend.BackendNotImplementedError: ...
The last possibility is if we don't have ``__ua_convert__``, in which case the job is left
up to ``__ua_function__``, but putting things back into arrays after conversion will not be
possible.
"""

from ._backend import *
from ._backend import *
from ._backend import _Function
Loading

0 comments on commit 27c0be4

Please sign in to comment.