started work on backend
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import math
|
||||
|
||||
from .info import __doc__
|
||||
from numpy.version import version as __version__
|
||||
|
||||
from .type_check import *
|
||||
from .index_tricks import *
|
||||
from .function_base import *
|
||||
from .mixins import *
|
||||
from .nanfunctions import *
|
||||
from .shape_base import *
|
||||
from .stride_tricks import *
|
||||
from .twodim_base import *
|
||||
from .ufunclike import *
|
||||
from .histograms import *
|
||||
|
||||
from . import scimath as emath
|
||||
from .polynomial import *
|
||||
#import convertcode
|
||||
from .utils import *
|
||||
from .arraysetops import *
|
||||
from .npyio import *
|
||||
from .financial import *
|
||||
from .arrayterator import Arrayterator
|
||||
from .arraypad import *
|
||||
from ._version import *
|
||||
from numpy.core._multiarray_umath import tracemalloc_domain
|
||||
|
||||
__all__ = ['emath', 'math', 'tracemalloc_domain']
|
||||
__all__ += type_check.__all__
|
||||
__all__ += index_tricks.__all__
|
||||
__all__ += function_base.__all__
|
||||
__all__ += mixins.__all__
|
||||
__all__ += shape_base.__all__
|
||||
__all__ += stride_tricks.__all__
|
||||
__all__ += twodim_base.__all__
|
||||
__all__ += ufunclike.__all__
|
||||
__all__ += arraypad.__all__
|
||||
__all__ += polynomial.__all__
|
||||
__all__ += utils.__all__
|
||||
__all__ += arraysetops.__all__
|
||||
__all__ += npyio.__all__
|
||||
__all__ += financial.__all__
|
||||
__all__ += nanfunctions.__all__
|
||||
__all__ += histograms.__all__
|
||||
|
||||
from numpy._pytesttester import PytestTester
|
||||
test = PytestTester(__name__)
|
||||
del PytestTester
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,794 @@
|
||||
"""A file interface for handling local and remote data files.
|
||||
|
||||
The goal of datasource is to abstract some of the file system operations
|
||||
when dealing with data files so the researcher doesn't have to know all the
|
||||
low-level details. Through datasource, a researcher can obtain and use a
|
||||
file with one function call, regardless of location of the file.
|
||||
|
||||
DataSource is meant to augment standard python libraries, not replace them.
|
||||
It should work seamlessly with standard file IO operations and the os
|
||||
module.
|
||||
|
||||
DataSource files can originate locally or remotely:
|
||||
|
||||
- local files : '/home/guido/src/local/data.txt'
|
||||
- URLs (http, ftp, ...) : 'http://www.scipy.org/not/real/data.txt'
|
||||
|
||||
DataSource files can also be compressed or uncompressed. Currently only
|
||||
gzip, bz2 and xz are supported.
|
||||
|
||||
Example::
|
||||
|
||||
>>> # Create a DataSource, use os.curdir (default) for local storage.
|
||||
>>> ds = datasource.DataSource()
|
||||
>>>
|
||||
>>> # Open a remote file.
|
||||
>>> # DataSource downloads the file, stores it locally in:
|
||||
>>> # './www.google.com/index.html'
|
||||
>>> # opens the file and returns a file object.
|
||||
>>> fp = ds.open('http://www.google.com/index.html')
|
||||
>>>
|
||||
>>> # Use the file as you normally would
|
||||
>>> fp.read()
|
||||
>>> fp.close()
|
||||
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
import shutil
|
||||
import io
|
||||
|
||||
from numpy.core.overrides import set_module
|
||||
|
||||
|
||||
_open = open
|
||||
|
||||
|
||||
def _check_mode(mode, encoding, newline):
|
||||
"""Check mode and that encoding and newline are compatible.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mode : str
|
||||
File open mode.
|
||||
encoding : str
|
||||
File encoding.
|
||||
newline : str
|
||||
Newline for text files.
|
||||
|
||||
"""
|
||||
if "t" in mode:
|
||||
if "b" in mode:
|
||||
raise ValueError("Invalid mode: %r" % (mode,))
|
||||
else:
|
||||
if encoding is not None:
|
||||
raise ValueError("Argument 'encoding' not supported in binary mode")
|
||||
if newline is not None:
|
||||
raise ValueError("Argument 'newline' not supported in binary mode")
|
||||
|
||||
|
||||
def _python2_bz2open(fn, mode, encoding, newline):
|
||||
"""Wrapper to open bz2 in text mode.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fn : str
|
||||
File name
|
||||
mode : {'r', 'w'}
|
||||
File mode. Note that bz2 Text files are not supported.
|
||||
encoding : str
|
||||
Ignored, text bz2 files not supported in Python2.
|
||||
newline : str
|
||||
Ignored, text bz2 files not supported in Python2.
|
||||
"""
|
||||
import bz2
|
||||
|
||||
_check_mode(mode, encoding, newline)
|
||||
|
||||
if "t" in mode:
|
||||
# BZ2File is missing necessary functions for TextIOWrapper
|
||||
warnings.warn("Assuming latin1 encoding for bz2 text file in Python2",
|
||||
RuntimeWarning, stacklevel=5)
|
||||
mode = mode.replace("t", "")
|
||||
return bz2.BZ2File(fn, mode)
|
||||
|
||||
def _python2_gzipopen(fn, mode, encoding, newline):
|
||||
""" Wrapper to open gzip in text mode.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fn : str, bytes, file
|
||||
File path or opened file.
|
||||
mode : str
|
||||
File mode. The actual files are opened as binary, but will decoded
|
||||
using the specified `encoding` and `newline`.
|
||||
encoding : str
|
||||
Encoding to be used when reading/writing as text.
|
||||
newline : str
|
||||
Newline to be used when reading/writing as text.
|
||||
|
||||
"""
|
||||
import gzip
|
||||
# gzip is lacking read1 needed for TextIOWrapper
|
||||
class GzipWrap(gzip.GzipFile):
|
||||
def read1(self, n):
|
||||
return self.read(n)
|
||||
|
||||
_check_mode(mode, encoding, newline)
|
||||
|
||||
gz_mode = mode.replace("t", "")
|
||||
|
||||
if isinstance(fn, (str, bytes)):
|
||||
binary_file = GzipWrap(fn, gz_mode)
|
||||
elif hasattr(fn, "read") or hasattr(fn, "write"):
|
||||
binary_file = GzipWrap(None, gz_mode, fileobj=fn)
|
||||
else:
|
||||
raise TypeError("filename must be a str or bytes object, or a file")
|
||||
|
||||
if "t" in mode:
|
||||
return io.TextIOWrapper(binary_file, encoding, newline=newline)
|
||||
else:
|
||||
return binary_file
|
||||
|
||||
|
||||
# Using a class instead of a module-level dictionary
|
||||
# to reduce the initial 'import numpy' overhead by
|
||||
# deferring the import of lzma, bz2 and gzip until needed
|
||||
|
||||
# TODO: .zip support, .tar support?
|
||||
class _FileOpeners(object):
|
||||
"""
|
||||
Container for different methods to open (un-)compressed files.
|
||||
|
||||
`_FileOpeners` contains a dictionary that holds one method for each
|
||||
supported file format. Attribute lookup is implemented in such a way
|
||||
that an instance of `_FileOpeners` itself can be indexed with the keys
|
||||
of that dictionary. Currently uncompressed files as well as files
|
||||
compressed with ``gzip``, ``bz2`` or ``xz`` compression are supported.
|
||||
|
||||
Notes
|
||||
-----
|
||||
`_file_openers`, an instance of `_FileOpeners`, is made available for
|
||||
use in the `_datasource` module.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.lib._datasource._file_openers.keys()
|
||||
[None, '.bz2', '.gz', '.xz', '.lzma']
|
||||
>>> np.lib._datasource._file_openers['.gz'] is gzip.open
|
||||
True
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._loaded = False
|
||||
self._file_openers = {None: io.open}
|
||||
|
||||
def _load(self):
|
||||
if self._loaded:
|
||||
return
|
||||
|
||||
try:
|
||||
import bz2
|
||||
if sys.version_info[0] >= 3:
|
||||
self._file_openers[".bz2"] = bz2.open
|
||||
else:
|
||||
self._file_openers[".bz2"] = _python2_bz2open
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
try:
|
||||
import gzip
|
||||
if sys.version_info[0] >= 3:
|
||||
self._file_openers[".gz"] = gzip.open
|
||||
else:
|
||||
self._file_openers[".gz"] = _python2_gzipopen
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
try:
|
||||
import lzma
|
||||
self._file_openers[".xz"] = lzma.open
|
||||
self._file_openers[".lzma"] = lzma.open
|
||||
except (ImportError, AttributeError):
|
||||
# There are incompatible backports of lzma that do not have the
|
||||
# lzma.open attribute, so catch that as well as ImportError.
|
||||
pass
|
||||
|
||||
self._loaded = True
|
||||
|
||||
def keys(self):
|
||||
"""
|
||||
Return the keys of currently supported file openers.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
None
|
||||
|
||||
Returns
|
||||
-------
|
||||
keys : list
|
||||
The keys are None for uncompressed files and the file extension
|
||||
strings (i.e. ``'.gz'``, ``'.xz'``) for supported compression
|
||||
methods.
|
||||
|
||||
"""
|
||||
self._load()
|
||||
return list(self._file_openers.keys())
|
||||
|
||||
def __getitem__(self, key):
|
||||
self._load()
|
||||
return self._file_openers[key]
|
||||
|
||||
_file_openers = _FileOpeners()
|
||||
|
||||
def open(path, mode='r', destpath=os.curdir, encoding=None, newline=None):
|
||||
"""
|
||||
Open `path` with `mode` and return the file object.
|
||||
|
||||
If ``path`` is an URL, it will be downloaded, stored in the
|
||||
`DataSource` `destpath` directory and opened from there.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : str
|
||||
Local file path or URL to open.
|
||||
mode : str, optional
|
||||
Mode to open `path`. Mode 'r' for reading, 'w' for writing, 'a' to
|
||||
append. Available modes depend on the type of object specified by
|
||||
path. Default is 'r'.
|
||||
destpath : str, optional
|
||||
Path to the directory where the source file gets downloaded to for
|
||||
use. If `destpath` is None, a temporary directory will be created.
|
||||
The default path is the current directory.
|
||||
encoding : {None, str}, optional
|
||||
Open text file with given encoding. The default encoding will be
|
||||
what `io.open` uses.
|
||||
newline : {None, str}, optional
|
||||
Newline to use when reading text file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : file object
|
||||
The opened file.
|
||||
|
||||
Notes
|
||||
-----
|
||||
This is a convenience function that instantiates a `DataSource` and
|
||||
returns the file object from ``DataSource.open(path)``.
|
||||
|
||||
"""
|
||||
|
||||
ds = DataSource(destpath)
|
||||
return ds.open(path, mode, encoding=encoding, newline=newline)
|
||||
|
||||
|
||||
@set_module('numpy')
|
||||
class DataSource(object):
|
||||
"""
|
||||
DataSource(destpath='.')
|
||||
|
||||
A generic data source file (file, http, ftp, ...).
|
||||
|
||||
DataSources can be local files or remote files/URLs. The files may
|
||||
also be compressed or uncompressed. DataSource hides some of the
|
||||
low-level details of downloading the file, allowing you to simply pass
|
||||
in a valid file path (or URL) and obtain a file object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
destpath : str or None, optional
|
||||
Path to the directory where the source file gets downloaded to for
|
||||
use. If `destpath` is None, a temporary directory will be created.
|
||||
The default path is the current directory.
|
||||
|
||||
Notes
|
||||
-----
|
||||
URLs require a scheme string (``http://``) to be used, without it they
|
||||
will fail::
|
||||
|
||||
>>> repos = DataSource()
|
||||
>>> repos.exists('www.google.com/index.html')
|
||||
False
|
||||
>>> repos.exists('http://www.google.com/index.html')
|
||||
True
|
||||
|
||||
Temporary directories are deleted when the DataSource is deleted.
|
||||
|
||||
Examples
|
||||
--------
|
||||
::
|
||||
|
||||
>>> ds = DataSource('/home/guido')
|
||||
>>> urlname = 'http://www.google.com/index.html'
|
||||
>>> gfile = ds.open('http://www.google.com/index.html') # remote file
|
||||
>>> ds.abspath(urlname)
|
||||
'/home/guido/www.google.com/site/index.html'
|
||||
|
||||
>>> ds = DataSource(None) # use with temporary file
|
||||
>>> ds.open('/home/guido/foobar.txt')
|
||||
<open file '/home/guido.foobar.txt', mode 'r' at 0x91d4430>
|
||||
>>> ds.abspath('/home/guido/foobar.txt')
|
||||
'/tmp/tmpy4pgsP/home/guido/foobar.txt'
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, destpath=os.curdir):
|
||||
"""Create a DataSource with a local path at destpath."""
|
||||
if destpath:
|
||||
self._destpath = os.path.abspath(destpath)
|
||||
self._istmpdest = False
|
||||
else:
|
||||
import tempfile # deferring import to improve startup time
|
||||
self._destpath = tempfile.mkdtemp()
|
||||
self._istmpdest = True
|
||||
|
||||
def __del__(self):
|
||||
# Remove temp directories
|
||||
if hasattr(self, '_istmpdest') and self._istmpdest:
|
||||
shutil.rmtree(self._destpath)
|
||||
|
||||
def _iszip(self, filename):
|
||||
"""Test if the filename is a zip file by looking at the file extension.
|
||||
|
||||
"""
|
||||
fname, ext = os.path.splitext(filename)
|
||||
return ext in _file_openers.keys()
|
||||
|
||||
def _iswritemode(self, mode):
|
||||
"""Test if the given mode will open a file for writing."""
|
||||
|
||||
# Currently only used to test the bz2 files.
|
||||
_writemodes = ("w", "+")
|
||||
for c in mode:
|
||||
if c in _writemodes:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _splitzipext(self, filename):
|
||||
"""Split zip extension from filename and return filename.
|
||||
|
||||
*Returns*:
|
||||
base, zip_ext : {tuple}
|
||||
|
||||
"""
|
||||
|
||||
if self._iszip(filename):
|
||||
return os.path.splitext(filename)
|
||||
else:
|
||||
return filename, None
|
||||
|
||||
def _possible_names(self, filename):
|
||||
"""Return a tuple containing compressed filename variations."""
|
||||
names = [filename]
|
||||
if not self._iszip(filename):
|
||||
for zipext in _file_openers.keys():
|
||||
if zipext:
|
||||
names.append(filename+zipext)
|
||||
return names
|
||||
|
||||
def _isurl(self, path):
|
||||
"""Test if path is a net location. Tests the scheme and netloc."""
|
||||
|
||||
# We do this here to reduce the 'import numpy' initial import time.
|
||||
if sys.version_info[0] >= 3:
|
||||
from urllib.parse import urlparse
|
||||
else:
|
||||
from urlparse import urlparse
|
||||
|
||||
# BUG : URLs require a scheme string ('http://') to be used.
|
||||
# www.google.com will fail.
|
||||
# Should we prepend the scheme for those that don't have it and
|
||||
# test that also? Similar to the way we append .gz and test for
|
||||
# for compressed versions of files.
|
||||
|
||||
scheme, netloc, upath, uparams, uquery, ufrag = urlparse(path)
|
||||
return bool(scheme and netloc)
|
||||
|
||||
def _cache(self, path):
|
||||
"""Cache the file specified by path.
|
||||
|
||||
Creates a copy of the file in the datasource cache.
|
||||
|
||||
"""
|
||||
# We import these here because importing urllib2 is slow and
|
||||
# a significant fraction of numpy's total import time.
|
||||
if sys.version_info[0] >= 3:
|
||||
from urllib.request import urlopen
|
||||
from urllib.error import URLError
|
||||
else:
|
||||
from urllib2 import urlopen
|
||||
from urllib2 import URLError
|
||||
|
||||
upath = self.abspath(path)
|
||||
|
||||
# ensure directory exists
|
||||
if not os.path.exists(os.path.dirname(upath)):
|
||||
os.makedirs(os.path.dirname(upath))
|
||||
|
||||
# TODO: Doesn't handle compressed files!
|
||||
if self._isurl(path):
|
||||
try:
|
||||
openedurl = urlopen(path)
|
||||
f = _open(upath, 'wb')
|
||||
try:
|
||||
shutil.copyfileobj(openedurl, f)
|
||||
finally:
|
||||
f.close()
|
||||
openedurl.close()
|
||||
except URLError:
|
||||
raise URLError("URL not found: %s" % path)
|
||||
else:
|
||||
shutil.copyfile(path, upath)
|
||||
return upath
|
||||
|
||||
def _findfile(self, path):
|
||||
"""Searches for ``path`` and returns full path if found.
|
||||
|
||||
If path is an URL, _findfile will cache a local copy and return the
|
||||
path to the cached file. If path is a local file, _findfile will
|
||||
return a path to that local file.
|
||||
|
||||
The search will include possible compressed versions of the file
|
||||
and return the first occurrence found.
|
||||
|
||||
"""
|
||||
|
||||
# Build list of possible local file paths
|
||||
if not self._isurl(path):
|
||||
# Valid local paths
|
||||
filelist = self._possible_names(path)
|
||||
# Paths in self._destpath
|
||||
filelist += self._possible_names(self.abspath(path))
|
||||
else:
|
||||
# Cached URLs in self._destpath
|
||||
filelist = self._possible_names(self.abspath(path))
|
||||
# Remote URLs
|
||||
filelist = filelist + self._possible_names(path)
|
||||
|
||||
for name in filelist:
|
||||
if self.exists(name):
|
||||
if self._isurl(name):
|
||||
name = self._cache(name)
|
||||
return name
|
||||
return None
|
||||
|
||||
def abspath(self, path):
|
||||
"""
|
||||
Return absolute path of file in the DataSource directory.
|
||||
|
||||
If `path` is an URL, then `abspath` will return either the location
|
||||
the file exists locally or the location it would exist when opened
|
||||
using the `open` method.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : str
|
||||
Can be a local file or a remote URL.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : str
|
||||
Complete path, including the `DataSource` destination directory.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The functionality is based on `os.path.abspath`.
|
||||
|
||||
"""
|
||||
# We do this here to reduce the 'import numpy' initial import time.
|
||||
if sys.version_info[0] >= 3:
|
||||
from urllib.parse import urlparse
|
||||
else:
|
||||
from urlparse import urlparse
|
||||
|
||||
# TODO: This should be more robust. Handles case where path includes
|
||||
# the destpath, but not other sub-paths. Failing case:
|
||||
# path = /home/guido/datafile.txt
|
||||
# destpath = /home/alex/
|
||||
# upath = self.abspath(path)
|
||||
# upath == '/home/alex/home/guido/datafile.txt'
|
||||
|
||||
# handle case where path includes self._destpath
|
||||
splitpath = path.split(self._destpath, 2)
|
||||
if len(splitpath) > 1:
|
||||
path = splitpath[1]
|
||||
scheme, netloc, upath, uparams, uquery, ufrag = urlparse(path)
|
||||
netloc = self._sanitize_relative_path(netloc)
|
||||
upath = self._sanitize_relative_path(upath)
|
||||
return os.path.join(self._destpath, netloc, upath)
|
||||
|
||||
def _sanitize_relative_path(self, path):
|
||||
"""Return a sanitised relative path for which
|
||||
os.path.abspath(os.path.join(base, path)).startswith(base)
|
||||
"""
|
||||
last = None
|
||||
path = os.path.normpath(path)
|
||||
while path != last:
|
||||
last = path
|
||||
# Note: os.path.join treats '/' as os.sep on Windows
|
||||
path = path.lstrip(os.sep).lstrip('/')
|
||||
path = path.lstrip(os.pardir).lstrip('..')
|
||||
drive, path = os.path.splitdrive(path) # for Windows
|
||||
return path
|
||||
|
||||
def exists(self, path):
|
||||
"""
|
||||
Test if path exists.
|
||||
|
||||
Test if `path` exists as (and in this order):
|
||||
|
||||
- a local file.
|
||||
- a remote URL that has been downloaded and stored locally in the
|
||||
`DataSource` directory.
|
||||
- a remote URL that has not been downloaded, but is valid and
|
||||
accessible.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : str
|
||||
Can be a local file or a remote URL.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : bool
|
||||
True if `path` exists.
|
||||
|
||||
Notes
|
||||
-----
|
||||
When `path` is an URL, `exists` will return True if it's either
|
||||
stored locally in the `DataSource` directory, or is a valid remote
|
||||
URL. `DataSource` does not discriminate between the two, the file
|
||||
is accessible if it exists in either location.
|
||||
|
||||
"""
|
||||
# We import this here because importing urllib2 is slow and
|
||||
# a significant fraction of numpy's total import time.
|
||||
if sys.version_info[0] >= 3:
|
||||
from urllib.request import urlopen
|
||||
from urllib.error import URLError
|
||||
else:
|
||||
from urllib2 import urlopen
|
||||
from urllib2 import URLError
|
||||
|
||||
# Test local path
|
||||
if os.path.exists(path):
|
||||
return True
|
||||
|
||||
# Test cached url
|
||||
upath = self.abspath(path)
|
||||
if os.path.exists(upath):
|
||||
return True
|
||||
|
||||
# Test remote url
|
||||
if self._isurl(path):
|
||||
try:
|
||||
netfile = urlopen(path)
|
||||
netfile.close()
|
||||
del(netfile)
|
||||
return True
|
||||
except URLError:
|
||||
return False
|
||||
return False
|
||||
|
||||
def open(self, path, mode='r', encoding=None, newline=None):
|
||||
"""
|
||||
Open and return file-like object.
|
||||
|
||||
If `path` is an URL, it will be downloaded, stored in the
|
||||
`DataSource` directory and opened from there.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : str
|
||||
Local file path or URL to open.
|
||||
mode : {'r', 'w', 'a'}, optional
|
||||
Mode to open `path`. Mode 'r' for reading, 'w' for writing,
|
||||
'a' to append. Available modes depend on the type of object
|
||||
specified by `path`. Default is 'r'.
|
||||
encoding : {None, str}, optional
|
||||
Open text file with given encoding. The default encoding will be
|
||||
what `io.open` uses.
|
||||
newline : {None, str}, optional
|
||||
Newline to use when reading text file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : file object
|
||||
File object.
|
||||
|
||||
"""
|
||||
|
||||
# TODO: There is no support for opening a file for writing which
|
||||
# doesn't exist yet (creating a file). Should there be?
|
||||
|
||||
# TODO: Add a ``subdir`` parameter for specifying the subdirectory
|
||||
# used to store URLs in self._destpath.
|
||||
|
||||
if self._isurl(path) and self._iswritemode(mode):
|
||||
raise ValueError("URLs are not writeable")
|
||||
|
||||
# NOTE: _findfile will fail on a new file opened for writing.
|
||||
found = self._findfile(path)
|
||||
if found:
|
||||
_fname, ext = self._splitzipext(found)
|
||||
if ext == 'bz2':
|
||||
mode.replace("+", "")
|
||||
return _file_openers[ext](found, mode=mode,
|
||||
encoding=encoding, newline=newline)
|
||||
else:
|
||||
raise IOError("%s not found." % path)
|
||||
|
||||
|
||||
class Repository (DataSource):
|
||||
"""
|
||||
Repository(baseurl, destpath='.')
|
||||
|
||||
A data repository where multiple DataSource's share a base
|
||||
URL/directory.
|
||||
|
||||
`Repository` extends `DataSource` by prepending a base URL (or
|
||||
directory) to all the files it handles. Use `Repository` when you will
|
||||
be working with multiple files from one base URL. Initialize
|
||||
`Repository` with the base URL, then refer to each file by its filename
|
||||
only.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
baseurl : str
|
||||
Path to the local directory or remote location that contains the
|
||||
data files.
|
||||
destpath : str or None, optional
|
||||
Path to the directory where the source file gets downloaded to for
|
||||
use. If `destpath` is None, a temporary directory will be created.
|
||||
The default path is the current directory.
|
||||
|
||||
Examples
|
||||
--------
|
||||
To analyze all files in the repository, do something like this
|
||||
(note: this is not self-contained code)::
|
||||
|
||||
>>> repos = np.lib._datasource.Repository('/home/user/data/dir/')
|
||||
>>> for filename in filelist:
|
||||
... fp = repos.open(filename)
|
||||
... fp.analyze()
|
||||
... fp.close()
|
||||
|
||||
Similarly you could use a URL for a repository::
|
||||
|
||||
>>> repos = np.lib._datasource.Repository('http://www.xyz.edu/data')
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, baseurl, destpath=os.curdir):
|
||||
"""Create a Repository with a shared url or directory of baseurl."""
|
||||
DataSource.__init__(self, destpath=destpath)
|
||||
self._baseurl = baseurl
|
||||
|
||||
def __del__(self):
|
||||
DataSource.__del__(self)
|
||||
|
||||
def _fullpath(self, path):
|
||||
"""Return complete path for path. Prepends baseurl if necessary."""
|
||||
splitpath = path.split(self._baseurl, 2)
|
||||
if len(splitpath) == 1:
|
||||
result = os.path.join(self._baseurl, path)
|
||||
else:
|
||||
result = path # path contains baseurl already
|
||||
return result
|
||||
|
||||
def _findfile(self, path):
|
||||
"""Extend DataSource method to prepend baseurl to ``path``."""
|
||||
return DataSource._findfile(self, self._fullpath(path))
|
||||
|
||||
def abspath(self, path):
|
||||
"""
|
||||
Return absolute path of file in the Repository directory.
|
||||
|
||||
If `path` is an URL, then `abspath` will return either the location
|
||||
the file exists locally or the location it would exist when opened
|
||||
using the `open` method.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : str
|
||||
Can be a local file or a remote URL. This may, but does not
|
||||
have to, include the `baseurl` with which the `Repository` was
|
||||
initialized.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : str
|
||||
Complete path, including the `DataSource` destination directory.
|
||||
|
||||
"""
|
||||
return DataSource.abspath(self, self._fullpath(path))
|
||||
|
||||
def exists(self, path):
|
||||
"""
|
||||
Test if path exists prepending Repository base URL to path.
|
||||
|
||||
Test if `path` exists as (and in this order):
|
||||
|
||||
- a local file.
|
||||
- a remote URL that has been downloaded and stored locally in the
|
||||
`DataSource` directory.
|
||||
- a remote URL that has not been downloaded, but is valid and
|
||||
accessible.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : str
|
||||
Can be a local file or a remote URL. This may, but does not
|
||||
have to, include the `baseurl` with which the `Repository` was
|
||||
initialized.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : bool
|
||||
True if `path` exists.
|
||||
|
||||
Notes
|
||||
-----
|
||||
When `path` is an URL, `exists` will return True if it's either
|
||||
stored locally in the `DataSource` directory, or is a valid remote
|
||||
URL. `DataSource` does not discriminate between the two, the file
|
||||
is accessible if it exists in either location.
|
||||
|
||||
"""
|
||||
return DataSource.exists(self, self._fullpath(path))
|
||||
|
||||
def open(self, path, mode='r', encoding=None, newline=None):
|
||||
"""
|
||||
Open and return file-like object prepending Repository base URL.
|
||||
|
||||
If `path` is an URL, it will be downloaded, stored in the
|
||||
DataSource directory and opened from there.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : str
|
||||
Local file path or URL to open. This may, but does not have to,
|
||||
include the `baseurl` with which the `Repository` was
|
||||
initialized.
|
||||
mode : {'r', 'w', 'a'}, optional
|
||||
Mode to open `path`. Mode 'r' for reading, 'w' for writing,
|
||||
'a' to append. Available modes depend on the type of object
|
||||
specified by `path`. Default is 'r'.
|
||||
encoding : {None, str}, optional
|
||||
Open text file with given encoding. The default encoding will be
|
||||
what `io.open` uses.
|
||||
newline : {None, str}, optional
|
||||
Newline to use when reading text file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : file object
|
||||
File object.
|
||||
|
||||
"""
|
||||
return DataSource.open(self, self._fullpath(path), mode,
|
||||
encoding=encoding, newline=newline)
|
||||
|
||||
def listdir(self):
|
||||
"""
|
||||
List files in the source Repository.
|
||||
|
||||
Returns
|
||||
-------
|
||||
files : list of str
|
||||
List of file names (not containing a directory part).
|
||||
|
||||
Notes
|
||||
-----
|
||||
Does not currently work for remote repositories.
|
||||
|
||||
"""
|
||||
if self._isurl(self._baseurl):
|
||||
raise NotImplementedError(
|
||||
"Directory listing of URLs, not supported yet.")
|
||||
else:
|
||||
return os.listdir(self._baseurl)
|
||||
@@ -0,0 +1,953 @@
|
||||
"""A collection of functions designed to help I/O with ascii files.
|
||||
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
__docformat__ = "restructuredtext en"
|
||||
|
||||
import sys
|
||||
import numpy as np
|
||||
import numpy.core.numeric as nx
|
||||
from numpy.compat import asbytes, asunicode, bytes, basestring
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
from builtins import bool, int, float, complex, object, str
|
||||
unicode = str
|
||||
else:
|
||||
from __builtin__ import bool, int, float, complex, object, unicode, str
|
||||
|
||||
|
||||
def _decode_line(line, encoding=None):
|
||||
"""Decode bytes from binary input streams.
|
||||
|
||||
Defaults to decoding from 'latin1'. That differs from the behavior of
|
||||
np.compat.asunicode that decodes from 'ascii'.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
line : str or bytes
|
||||
Line to be decoded.
|
||||
|
||||
Returns
|
||||
-------
|
||||
decoded_line : unicode
|
||||
Unicode in Python 2, a str (unicode) in Python 3.
|
||||
|
||||
"""
|
||||
if type(line) is bytes:
|
||||
if encoding is None:
|
||||
line = line.decode('latin1')
|
||||
else:
|
||||
line = line.decode(encoding)
|
||||
|
||||
return line
|
||||
|
||||
|
||||
def _is_string_like(obj):
|
||||
"""
|
||||
Check whether obj behaves like a string.
|
||||
"""
|
||||
try:
|
||||
obj + ''
|
||||
except (TypeError, ValueError):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _is_bytes_like(obj):
|
||||
"""
|
||||
Check whether obj behaves like a bytes object.
|
||||
"""
|
||||
try:
|
||||
obj + b''
|
||||
except (TypeError, ValueError):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _to_filehandle(fname, flag='r', return_opened=False):
|
||||
"""
|
||||
Returns the filehandle corresponding to a string or a file.
|
||||
If the string ends in '.gz', the file is automatically unzipped.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : string, filehandle
|
||||
Name of the file whose filehandle must be returned.
|
||||
flag : string, optional
|
||||
Flag indicating the status of the file ('r' for read, 'w' for write).
|
||||
return_opened : boolean, optional
|
||||
Whether to return the opening status of the file.
|
||||
"""
|
||||
if _is_string_like(fname):
|
||||
if fname.endswith('.gz'):
|
||||
import gzip
|
||||
fhd = gzip.open(fname, flag)
|
||||
elif fname.endswith('.bz2'):
|
||||
import bz2
|
||||
fhd = bz2.BZ2File(fname)
|
||||
else:
|
||||
fhd = file(fname, flag)
|
||||
opened = True
|
||||
elif hasattr(fname, 'seek'):
|
||||
fhd = fname
|
||||
opened = False
|
||||
else:
|
||||
raise ValueError('fname must be a string or file handle')
|
||||
if return_opened:
|
||||
return fhd, opened
|
||||
return fhd
|
||||
|
||||
|
||||
def has_nested_fields(ndtype):
|
||||
"""
|
||||
Returns whether one or several fields of a dtype are nested.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ndtype : dtype
|
||||
Data-type of a structured array.
|
||||
|
||||
Raises
|
||||
------
|
||||
AttributeError
|
||||
If `ndtype` does not have a `names` attribute.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> dt = np.dtype([('name', 'S4'), ('x', float), ('y', float)])
|
||||
>>> np.lib._iotools.has_nested_fields(dt)
|
||||
False
|
||||
|
||||
"""
|
||||
for name in ndtype.names or ():
|
||||
if ndtype[name].names:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def flatten_dtype(ndtype, flatten_base=False):
|
||||
"""
|
||||
Unpack a structured data-type by collapsing nested fields and/or fields
|
||||
with a shape.
|
||||
|
||||
Note that the field names are lost.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ndtype : dtype
|
||||
The datatype to collapse
|
||||
flatten_base : bool, optional
|
||||
If True, transform a field with a shape into several fields. Default is
|
||||
False.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> dt = np.dtype([('name', 'S4'), ('x', float), ('y', float),
|
||||
... ('block', int, (2, 3))])
|
||||
>>> np.lib._iotools.flatten_dtype(dt)
|
||||
[dtype('|S4'), dtype('float64'), dtype('float64'), dtype('int32')]
|
||||
>>> np.lib._iotools.flatten_dtype(dt, flatten_base=True)
|
||||
[dtype('|S4'), dtype('float64'), dtype('float64'), dtype('int32'),
|
||||
dtype('int32'), dtype('int32'), dtype('int32'), dtype('int32'),
|
||||
dtype('int32')]
|
||||
|
||||
"""
|
||||
names = ndtype.names
|
||||
if names is None:
|
||||
if flatten_base:
|
||||
return [ndtype.base] * int(np.prod(ndtype.shape))
|
||||
return [ndtype.base]
|
||||
else:
|
||||
types = []
|
||||
for field in names:
|
||||
info = ndtype.fields[field]
|
||||
flat_dt = flatten_dtype(info[0], flatten_base)
|
||||
types.extend(flat_dt)
|
||||
return types
|
||||
|
||||
|
||||
class LineSplitter(object):
|
||||
"""
|
||||
Object to split a string at a given delimiter or at given places.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
delimiter : str, int, or sequence of ints, optional
|
||||
If a string, character used to delimit consecutive fields.
|
||||
If an integer or a sequence of integers, width(s) of each field.
|
||||
comments : str, optional
|
||||
Character used to mark the beginning of a comment. Default is '#'.
|
||||
autostrip : bool, optional
|
||||
Whether to strip each individual field. Default is True.
|
||||
|
||||
"""
|
||||
|
||||
def autostrip(self, method):
|
||||
"""
|
||||
Wrapper to strip each member of the output of `method`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
method : function
|
||||
Function that takes a single argument and returns a sequence of
|
||||
strings.
|
||||
|
||||
Returns
|
||||
-------
|
||||
wrapped : function
|
||||
The result of wrapping `method`. `wrapped` takes a single input
|
||||
argument and returns a list of strings that are stripped of
|
||||
white-space.
|
||||
|
||||
"""
|
||||
return lambda input: [_.strip() for _ in method(input)]
|
||||
#
|
||||
|
||||
def __init__(self, delimiter=None, comments='#', autostrip=True, encoding=None):
|
||||
delimiter = _decode_line(delimiter)
|
||||
comments = _decode_line(comments)
|
||||
|
||||
self.comments = comments
|
||||
|
||||
# Delimiter is a character
|
||||
if (delimiter is None) or isinstance(delimiter, basestring):
|
||||
delimiter = delimiter or None
|
||||
_handyman = self._delimited_splitter
|
||||
# Delimiter is a list of field widths
|
||||
elif hasattr(delimiter, '__iter__'):
|
||||
_handyman = self._variablewidth_splitter
|
||||
idx = np.cumsum([0] + list(delimiter))
|
||||
delimiter = [slice(i, j) for (i, j) in zip(idx[:-1], idx[1:])]
|
||||
# Delimiter is a single integer
|
||||
elif int(delimiter):
|
||||
(_handyman, delimiter) = (
|
||||
self._fixedwidth_splitter, int(delimiter))
|
||||
else:
|
||||
(_handyman, delimiter) = (self._delimited_splitter, None)
|
||||
self.delimiter = delimiter
|
||||
if autostrip:
|
||||
self._handyman = self.autostrip(_handyman)
|
||||
else:
|
||||
self._handyman = _handyman
|
||||
self.encoding = encoding
|
||||
#
|
||||
|
||||
def _delimited_splitter(self, line):
|
||||
"""Chop off comments, strip, and split at delimiter. """
|
||||
if self.comments is not None:
|
||||
line = line.split(self.comments)[0]
|
||||
line = line.strip(" \r\n")
|
||||
if not line:
|
||||
return []
|
||||
return line.split(self.delimiter)
|
||||
#
|
||||
|
||||
def _fixedwidth_splitter(self, line):
|
||||
if self.comments is not None:
|
||||
line = line.split(self.comments)[0]
|
||||
line = line.strip("\r\n")
|
||||
if not line:
|
||||
return []
|
||||
fixed = self.delimiter
|
||||
slices = [slice(i, i + fixed) for i in range(0, len(line), fixed)]
|
||||
return [line[s] for s in slices]
|
||||
#
|
||||
|
||||
def _variablewidth_splitter(self, line):
|
||||
if self.comments is not None:
|
||||
line = line.split(self.comments)[0]
|
||||
if not line:
|
||||
return []
|
||||
slices = self.delimiter
|
||||
return [line[s] for s in slices]
|
||||
#
|
||||
|
||||
def __call__(self, line):
|
||||
return self._handyman(_decode_line(line, self.encoding))
|
||||
|
||||
|
||||
class NameValidator(object):
|
||||
"""
|
||||
Object to validate a list of strings to use as field names.
|
||||
|
||||
The strings are stripped of any non alphanumeric character, and spaces
|
||||
are replaced by '_'. During instantiation, the user can define a list
|
||||
of names to exclude, as well as a list of invalid characters. Names in
|
||||
the exclusion list are appended a '_' character.
|
||||
|
||||
Once an instance has been created, it can be called with a list of
|
||||
names, and a list of valid names will be created. The `__call__`
|
||||
method accepts an optional keyword "default" that sets the default name
|
||||
in case of ambiguity. By default this is 'f', so that names will
|
||||
default to `f0`, `f1`, etc.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
excludelist : sequence, optional
|
||||
A list of names to exclude. This list is appended to the default
|
||||
list ['return', 'file', 'print']. Excluded names are appended an
|
||||
underscore: for example, `file` becomes `file_` if supplied.
|
||||
deletechars : str, optional
|
||||
A string combining invalid characters that must be deleted from the
|
||||
names.
|
||||
case_sensitive : {True, False, 'upper', 'lower'}, optional
|
||||
* If True, field names are case-sensitive.
|
||||
* If False or 'upper', field names are converted to upper case.
|
||||
* If 'lower', field names are converted to lower case.
|
||||
|
||||
The default value is True.
|
||||
replace_space : '_', optional
|
||||
Character(s) used in replacement of white spaces.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Calling an instance of `NameValidator` is the same as calling its
|
||||
method `validate`.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> validator = np.lib._iotools.NameValidator()
|
||||
>>> validator(['file', 'field2', 'with space', 'CaSe'])
|
||||
['file_', 'field2', 'with_space', 'CaSe']
|
||||
|
||||
>>> validator = np.lib._iotools.NameValidator(excludelist=['excl'],
|
||||
deletechars='q',
|
||||
case_sensitive='False')
|
||||
>>> validator(['excl', 'field2', 'no_q', 'with space', 'CaSe'])
|
||||
['excl_', 'field2', 'no_', 'with_space', 'case']
|
||||
|
||||
"""
|
||||
#
|
||||
defaultexcludelist = ['return', 'file', 'print']
|
||||
defaultdeletechars = set(r"""~!@#$%^&*()-=+~\|]}[{';: /?.>,<""")
|
||||
#
|
||||
|
||||
def __init__(self, excludelist=None, deletechars=None,
|
||||
case_sensitive=None, replace_space='_'):
|
||||
# Process the exclusion list ..
|
||||
if excludelist is None:
|
||||
excludelist = []
|
||||
excludelist.extend(self.defaultexcludelist)
|
||||
self.excludelist = excludelist
|
||||
# Process the list of characters to delete
|
||||
if deletechars is None:
|
||||
delete = self.defaultdeletechars
|
||||
else:
|
||||
delete = set(deletechars)
|
||||
delete.add('"')
|
||||
self.deletechars = delete
|
||||
# Process the case option .....
|
||||
if (case_sensitive is None) or (case_sensitive is True):
|
||||
self.case_converter = lambda x: x
|
||||
elif (case_sensitive is False) or case_sensitive.startswith('u'):
|
||||
self.case_converter = lambda x: x.upper()
|
||||
elif case_sensitive.startswith('l'):
|
||||
self.case_converter = lambda x: x.lower()
|
||||
else:
|
||||
msg = 'unrecognized case_sensitive value %s.' % case_sensitive
|
||||
raise ValueError(msg)
|
||||
#
|
||||
self.replace_space = replace_space
|
||||
|
||||
def validate(self, names, defaultfmt="f%i", nbfields=None):
|
||||
"""
|
||||
Validate a list of strings as field names for a structured array.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
names : sequence of str
|
||||
Strings to be validated.
|
||||
defaultfmt : str, optional
|
||||
Default format string, used if validating a given string
|
||||
reduces its length to zero.
|
||||
nbfields : integer, optional
|
||||
Final number of validated names, used to expand or shrink the
|
||||
initial list of names.
|
||||
|
||||
Returns
|
||||
-------
|
||||
validatednames : list of str
|
||||
The list of validated field names.
|
||||
|
||||
Notes
|
||||
-----
|
||||
A `NameValidator` instance can be called directly, which is the
|
||||
same as calling `validate`. For examples, see `NameValidator`.
|
||||
|
||||
"""
|
||||
# Initial checks ..............
|
||||
if (names is None):
|
||||
if (nbfields is None):
|
||||
return None
|
||||
names = []
|
||||
if isinstance(names, basestring):
|
||||
names = [names, ]
|
||||
if nbfields is not None:
|
||||
nbnames = len(names)
|
||||
if (nbnames < nbfields):
|
||||
names = list(names) + [''] * (nbfields - nbnames)
|
||||
elif (nbnames > nbfields):
|
||||
names = names[:nbfields]
|
||||
# Set some shortcuts ...........
|
||||
deletechars = self.deletechars
|
||||
excludelist = self.excludelist
|
||||
case_converter = self.case_converter
|
||||
replace_space = self.replace_space
|
||||
# Initializes some variables ...
|
||||
validatednames = []
|
||||
seen = dict()
|
||||
nbempty = 0
|
||||
#
|
||||
for item in names:
|
||||
item = case_converter(item).strip()
|
||||
if replace_space:
|
||||
item = item.replace(' ', replace_space)
|
||||
item = ''.join([c for c in item if c not in deletechars])
|
||||
if item == '':
|
||||
item = defaultfmt % nbempty
|
||||
while item in names:
|
||||
nbempty += 1
|
||||
item = defaultfmt % nbempty
|
||||
nbempty += 1
|
||||
elif item in excludelist:
|
||||
item += '_'
|
||||
cnt = seen.get(item, 0)
|
||||
if cnt > 0:
|
||||
validatednames.append(item + '_%d' % cnt)
|
||||
else:
|
||||
validatednames.append(item)
|
||||
seen[item] = cnt + 1
|
||||
return tuple(validatednames)
|
||||
#
|
||||
|
||||
def __call__(self, names, defaultfmt="f%i", nbfields=None):
|
||||
return self.validate(names, defaultfmt=defaultfmt, nbfields=nbfields)
|
||||
|
||||
|
||||
def str2bool(value):
|
||||
"""
|
||||
Tries to transform a string supposed to represent a boolean to a boolean.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
value : str
|
||||
The string that is transformed to a boolean.
|
||||
|
||||
Returns
|
||||
-------
|
||||
boolval : bool
|
||||
The boolean representation of `value`.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If the string is not 'True' or 'False' (case independent)
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.lib._iotools.str2bool('TRUE')
|
||||
True
|
||||
>>> np.lib._iotools.str2bool('false')
|
||||
False
|
||||
|
||||
"""
|
||||
value = value.upper()
|
||||
if value == 'TRUE':
|
||||
return True
|
||||
elif value == 'FALSE':
|
||||
return False
|
||||
else:
|
||||
raise ValueError("Invalid boolean")
|
||||
|
||||
|
||||
class ConverterError(Exception):
|
||||
"""
|
||||
Exception raised when an error occurs in a converter for string values.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class ConverterLockError(ConverterError):
|
||||
"""
|
||||
Exception raised when an attempt is made to upgrade a locked converter.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class ConversionWarning(UserWarning):
|
||||
"""
|
||||
Warning issued when a string converter has a problem.
|
||||
|
||||
Notes
|
||||
-----
|
||||
In `genfromtxt` a `ConversionWarning` is issued if raising exceptions
|
||||
is explicitly suppressed with the "invalid_raise" keyword.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class StringConverter(object):
|
||||
"""
|
||||
Factory class for function transforming a string into another object
|
||||
(int, float).
|
||||
|
||||
After initialization, an instance can be called to transform a string
|
||||
into another object. If the string is recognized as representing a
|
||||
missing value, a default value is returned.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
func : function
|
||||
Function used for the conversion.
|
||||
default : any
|
||||
Default value to return when the input corresponds to a missing
|
||||
value.
|
||||
type : type
|
||||
Type of the output.
|
||||
_status : int
|
||||
Integer representing the order of the conversion.
|
||||
_mapper : sequence of tuples
|
||||
Sequence of tuples (dtype, function, default value) to evaluate in
|
||||
order.
|
||||
_locked : bool
|
||||
Holds `locked` parameter.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
dtype_or_func : {None, dtype, function}, optional
|
||||
If a `dtype`, specifies the input data type, used to define a basic
|
||||
function and a default value for missing data. For example, when
|
||||
`dtype` is float, the `func` attribute is set to `float` and the
|
||||
default value to `np.nan`. If a function, this function is used to
|
||||
convert a string to another object. In this case, it is recommended
|
||||
to give an associated default value as input.
|
||||
default : any, optional
|
||||
Value to return by default, that is, when the string to be
|
||||
converted is flagged as missing. If not given, `StringConverter`
|
||||
tries to supply a reasonable default value.
|
||||
missing_values : {None, sequence of str}, optional
|
||||
``None`` or sequence of strings indicating a missing value. If ``None``
|
||||
then missing values are indicated by empty entries. The default is
|
||||
``None``.
|
||||
locked : bool, optional
|
||||
Whether the StringConverter should be locked to prevent automatic
|
||||
upgrade or not. Default is False.
|
||||
|
||||
"""
|
||||
#
|
||||
_mapper = [(nx.bool_, str2bool, False),
|
||||
(nx.integer, int, -1)]
|
||||
|
||||
# On 32-bit systems, we need to make sure that we explicitly include
|
||||
# nx.int64 since ns.integer is nx.int32.
|
||||
if nx.dtype(nx.integer).itemsize < nx.dtype(nx.int64).itemsize:
|
||||
_mapper.append((nx.int64, int, -1))
|
||||
|
||||
_mapper.extend([(nx.floating, float, nx.nan),
|
||||
(nx.complexfloating, complex, nx.nan + 0j),
|
||||
(nx.longdouble, nx.longdouble, nx.nan),
|
||||
(nx.unicode_, asunicode, '???'),
|
||||
(nx.string_, asbytes, '???')])
|
||||
|
||||
(_defaulttype, _defaultfunc, _defaultfill) = zip(*_mapper)
|
||||
|
||||
@classmethod
|
||||
def _getdtype(cls, val):
|
||||
"""Returns the dtype of the input variable."""
|
||||
return np.array(val).dtype
|
||||
#
|
||||
|
||||
@classmethod
|
||||
def _getsubdtype(cls, val):
|
||||
"""Returns the type of the dtype of the input variable."""
|
||||
return np.array(val).dtype.type
|
||||
#
|
||||
# This is a bit annoying. We want to return the "general" type in most
|
||||
# cases (ie. "string" rather than "S10"), but we want to return the
|
||||
# specific type for datetime64 (ie. "datetime64[us]" rather than
|
||||
# "datetime64").
|
||||
|
||||
@classmethod
|
||||
def _dtypeortype(cls, dtype):
|
||||
"""Returns dtype for datetime64 and type of dtype otherwise."""
|
||||
if dtype.type == np.datetime64:
|
||||
return dtype
|
||||
return dtype.type
|
||||
#
|
||||
|
||||
@classmethod
|
||||
def upgrade_mapper(cls, func, default=None):
|
||||
"""
|
||||
Upgrade the mapper of a StringConverter by adding a new function and
|
||||
its corresponding default.
|
||||
|
||||
The input function (or sequence of functions) and its associated
|
||||
default value (if any) is inserted in penultimate position of the
|
||||
mapper. The corresponding type is estimated from the dtype of the
|
||||
default value.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
func : var
|
||||
Function, or sequence of functions
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> import dateutil.parser
|
||||
>>> import datetime
|
||||
>>> dateparser = datetustil.parser.parse
|
||||
>>> defaultdate = datetime.date(2000, 1, 1)
|
||||
>>> StringConverter.upgrade_mapper(dateparser, default=defaultdate)
|
||||
"""
|
||||
# Func is a single functions
|
||||
if hasattr(func, '__call__'):
|
||||
cls._mapper.insert(-1, (cls._getsubdtype(default), func, default))
|
||||
return
|
||||
elif hasattr(func, '__iter__'):
|
||||
if isinstance(func[0], (tuple, list)):
|
||||
for _ in func:
|
||||
cls._mapper.insert(-1, _)
|
||||
return
|
||||
if default is None:
|
||||
default = [None] * len(func)
|
||||
else:
|
||||
default = list(default)
|
||||
default.append([None] * (len(func) - len(default)))
|
||||
for (fct, dft) in zip(func, default):
|
||||
cls._mapper.insert(-1, (cls._getsubdtype(dft), fct, dft))
|
||||
#
|
||||
|
||||
def __init__(self, dtype_or_func=None, default=None, missing_values=None,
|
||||
locked=False):
|
||||
# Defines a lock for upgrade
|
||||
self._locked = bool(locked)
|
||||
# No input dtype: minimal initialization
|
||||
if dtype_or_func is None:
|
||||
self.func = str2bool
|
||||
self._status = 0
|
||||
self.default = default or False
|
||||
dtype = np.dtype('bool')
|
||||
else:
|
||||
# Is the input a np.dtype ?
|
||||
try:
|
||||
self.func = None
|
||||
dtype = np.dtype(dtype_or_func)
|
||||
except TypeError:
|
||||
# dtype_or_func must be a function, then
|
||||
if not hasattr(dtype_or_func, '__call__'):
|
||||
errmsg = ("The input argument `dtype` is neither a"
|
||||
" function nor a dtype (got '%s' instead)")
|
||||
raise TypeError(errmsg % type(dtype_or_func))
|
||||
# Set the function
|
||||
self.func = dtype_or_func
|
||||
# If we don't have a default, try to guess it or set it to
|
||||
# None
|
||||
if default is None:
|
||||
try:
|
||||
default = self.func('0')
|
||||
except ValueError:
|
||||
default = None
|
||||
dtype = self._getdtype(default)
|
||||
# Set the status according to the dtype
|
||||
_status = -1
|
||||
for (i, (deftype, func, default_def)) in enumerate(self._mapper):
|
||||
if np.issubdtype(dtype.type, deftype):
|
||||
_status = i
|
||||
if default is None:
|
||||
self.default = default_def
|
||||
else:
|
||||
self.default = default
|
||||
break
|
||||
# if a converter for the specific dtype is available use that
|
||||
last_func = func
|
||||
for (i, (deftype, func, default_def)) in enumerate(self._mapper):
|
||||
if dtype.type == deftype:
|
||||
_status = i
|
||||
last_func = func
|
||||
if default is None:
|
||||
self.default = default_def
|
||||
else:
|
||||
self.default = default
|
||||
break
|
||||
func = last_func
|
||||
if _status == -1:
|
||||
# We never found a match in the _mapper...
|
||||
_status = 0
|
||||
self.default = default
|
||||
self._status = _status
|
||||
# If the input was a dtype, set the function to the last we saw
|
||||
if self.func is None:
|
||||
self.func = func
|
||||
# If the status is 1 (int), change the function to
|
||||
# something more robust.
|
||||
if self.func == self._mapper[1][1]:
|
||||
if issubclass(dtype.type, np.uint64):
|
||||
self.func = np.uint64
|
||||
elif issubclass(dtype.type, np.int64):
|
||||
self.func = np.int64
|
||||
else:
|
||||
self.func = lambda x: int(float(x))
|
||||
# Store the list of strings corresponding to missing values.
|
||||
if missing_values is None:
|
||||
self.missing_values = {''}
|
||||
else:
|
||||
if isinstance(missing_values, basestring):
|
||||
missing_values = missing_values.split(",")
|
||||
self.missing_values = set(list(missing_values) + [''])
|
||||
#
|
||||
self._callingfunction = self._strict_call
|
||||
self.type = self._dtypeortype(dtype)
|
||||
self._checked = False
|
||||
self._initial_default = default
|
||||
#
|
||||
|
||||
def _loose_call(self, value):
|
||||
try:
|
||||
return self.func(value)
|
||||
except ValueError:
|
||||
return self.default
|
||||
#
|
||||
|
||||
def _strict_call(self, value):
|
||||
try:
|
||||
|
||||
# We check if we can convert the value using the current function
|
||||
new_value = self.func(value)
|
||||
|
||||
# In addition to having to check whether func can convert the
|
||||
# value, we also have to make sure that we don't get overflow
|
||||
# errors for integers.
|
||||
if self.func is int:
|
||||
try:
|
||||
np.array(value, dtype=self.type)
|
||||
except OverflowError:
|
||||
raise ValueError
|
||||
|
||||
# We're still here so we can now return the new value
|
||||
return new_value
|
||||
|
||||
except ValueError:
|
||||
if value.strip() in self.missing_values:
|
||||
if not self._status:
|
||||
self._checked = False
|
||||
return self.default
|
||||
raise ValueError("Cannot convert string '%s'" % value)
|
||||
#
|
||||
|
||||
def __call__(self, value):
|
||||
return self._callingfunction(value)
|
||||
#
|
||||
|
||||
def upgrade(self, value):
|
||||
"""
|
||||
Find the best converter for a given string, and return the result.
|
||||
|
||||
The supplied string `value` is converted by testing different
|
||||
converters in order. First the `func` method of the
|
||||
`StringConverter` instance is tried, if this fails other available
|
||||
converters are tried. The order in which these other converters
|
||||
are tried is determined by the `_status` attribute of the instance.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
value : str
|
||||
The string to convert.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : any
|
||||
The result of converting `value` with the appropriate converter.
|
||||
|
||||
"""
|
||||
self._checked = True
|
||||
try:
|
||||
return self._strict_call(value)
|
||||
except ValueError:
|
||||
# Raise an exception if we locked the converter...
|
||||
if self._locked:
|
||||
errmsg = "Converter is locked and cannot be upgraded"
|
||||
raise ConverterLockError(errmsg)
|
||||
_statusmax = len(self._mapper)
|
||||
# Complains if we try to upgrade by the maximum
|
||||
_status = self._status
|
||||
if _status == _statusmax:
|
||||
errmsg = "Could not find a valid conversion function"
|
||||
raise ConverterError(errmsg)
|
||||
elif _status < _statusmax - 1:
|
||||
_status += 1
|
||||
(self.type, self.func, default) = self._mapper[_status]
|
||||
self._status = _status
|
||||
if self._initial_default is not None:
|
||||
self.default = self._initial_default
|
||||
else:
|
||||
self.default = default
|
||||
return self.upgrade(value)
|
||||
|
||||
def iterupgrade(self, value):
|
||||
self._checked = True
|
||||
if not hasattr(value, '__iter__'):
|
||||
value = (value,)
|
||||
_strict_call = self._strict_call
|
||||
try:
|
||||
for _m in value:
|
||||
_strict_call(_m)
|
||||
except ValueError:
|
||||
# Raise an exception if we locked the converter...
|
||||
if self._locked:
|
||||
errmsg = "Converter is locked and cannot be upgraded"
|
||||
raise ConverterLockError(errmsg)
|
||||
_statusmax = len(self._mapper)
|
||||
# Complains if we try to upgrade by the maximum
|
||||
_status = self._status
|
||||
if _status == _statusmax:
|
||||
raise ConverterError(
|
||||
"Could not find a valid conversion function"
|
||||
)
|
||||
elif _status < _statusmax - 1:
|
||||
_status += 1
|
||||
(self.type, self.func, default) = self._mapper[_status]
|
||||
if self._initial_default is not None:
|
||||
self.default = self._initial_default
|
||||
else:
|
||||
self.default = default
|
||||
self._status = _status
|
||||
self.iterupgrade(value)
|
||||
|
||||
def update(self, func, default=None, testing_value=None,
|
||||
missing_values='', locked=False):
|
||||
"""
|
||||
Set StringConverter attributes directly.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
func : function
|
||||
Conversion function.
|
||||
default : any, optional
|
||||
Value to return by default, that is, when the string to be
|
||||
converted is flagged as missing. If not given,
|
||||
`StringConverter` tries to supply a reasonable default value.
|
||||
testing_value : str, optional
|
||||
A string representing a standard input value of the converter.
|
||||
This string is used to help defining a reasonable default
|
||||
value.
|
||||
missing_values : {sequence of str, None}, optional
|
||||
Sequence of strings indicating a missing value. If ``None``, then
|
||||
the existing `missing_values` are cleared. The default is `''`.
|
||||
locked : bool, optional
|
||||
Whether the StringConverter should be locked to prevent
|
||||
automatic upgrade or not. Default is False.
|
||||
|
||||
Notes
|
||||
-----
|
||||
`update` takes the same parameters as the constructor of
|
||||
`StringConverter`, except that `func` does not accept a `dtype`
|
||||
whereas `dtype_or_func` in the constructor does.
|
||||
|
||||
"""
|
||||
self.func = func
|
||||
self._locked = locked
|
||||
|
||||
# Don't reset the default to None if we can avoid it
|
||||
if default is not None:
|
||||
self.default = default
|
||||
self.type = self._dtypeortype(self._getdtype(default))
|
||||
else:
|
||||
try:
|
||||
tester = func(testing_value or '1')
|
||||
except (TypeError, ValueError):
|
||||
tester = None
|
||||
self.type = self._dtypeortype(self._getdtype(tester))
|
||||
|
||||
# Add the missing values to the existing set or clear it.
|
||||
if missing_values is None:
|
||||
# Clear all missing values even though the ctor initializes it to
|
||||
# set(['']) when the argument is None.
|
||||
self.missing_values = set()
|
||||
else:
|
||||
if not np.iterable(missing_values):
|
||||
missing_values = [missing_values]
|
||||
if not all(isinstance(v, basestring) for v in missing_values):
|
||||
raise TypeError("missing_values must be strings or unicode")
|
||||
self.missing_values.update(missing_values)
|
||||
|
||||
|
||||
def easy_dtype(ndtype, names=None, defaultfmt="f%i", **validationargs):
|
||||
"""
|
||||
Convenience function to create a `np.dtype` object.
|
||||
|
||||
The function processes the input `dtype` and matches it with the given
|
||||
names.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ndtype : var
|
||||
Definition of the dtype. Can be any string or dictionary recognized
|
||||
by the `np.dtype` function, or a sequence of types.
|
||||
names : str or sequence, optional
|
||||
Sequence of strings to use as field names for a structured dtype.
|
||||
For convenience, `names` can be a string of a comma-separated list
|
||||
of names.
|
||||
defaultfmt : str, optional
|
||||
Format string used to define missing names, such as ``"f%i"``
|
||||
(default) or ``"fields_%02i"``.
|
||||
validationargs : optional
|
||||
A series of optional arguments used to initialize a
|
||||
`NameValidator`.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.lib._iotools.easy_dtype(float)
|
||||
dtype('float64')
|
||||
>>> np.lib._iotools.easy_dtype("i4, f8")
|
||||
dtype([('f0', '<i4'), ('f1', '<f8')])
|
||||
>>> np.lib._iotools.easy_dtype("i4, f8", defaultfmt="field_%03i")
|
||||
dtype([('field_000', '<i4'), ('field_001', '<f8')])
|
||||
|
||||
>>> np.lib._iotools.easy_dtype((int, float, float), names="a,b,c")
|
||||
dtype([('a', '<i8'), ('b', '<f8'), ('c', '<f8')])
|
||||
>>> np.lib._iotools.easy_dtype(float, names="a,b,c")
|
||||
dtype([('a', '<f8'), ('b', '<f8'), ('c', '<f8')])
|
||||
|
||||
"""
|
||||
try:
|
||||
ndtype = np.dtype(ndtype)
|
||||
except TypeError:
|
||||
validate = NameValidator(**validationargs)
|
||||
nbfields = len(ndtype)
|
||||
if names is None:
|
||||
names = [''] * len(ndtype)
|
||||
elif isinstance(names, basestring):
|
||||
names = names.split(",")
|
||||
names = validate(names, nbfields=nbfields, defaultfmt=defaultfmt)
|
||||
ndtype = np.dtype(dict(formats=ndtype, names=names))
|
||||
else:
|
||||
nbtypes = len(ndtype)
|
||||
# Explicit names
|
||||
if names is not None:
|
||||
validate = NameValidator(**validationargs)
|
||||
if isinstance(names, basestring):
|
||||
names = names.split(",")
|
||||
# Simple dtype: repeat to match the nb of names
|
||||
if nbtypes == 0:
|
||||
formats = tuple([ndtype.type] * len(names))
|
||||
names = validate(names, defaultfmt=defaultfmt)
|
||||
ndtype = np.dtype(list(zip(names, formats)))
|
||||
# Structured dtype: just validate the names as needed
|
||||
else:
|
||||
ndtype.names = validate(names, nbfields=nbtypes,
|
||||
defaultfmt=defaultfmt)
|
||||
# No implicit names
|
||||
elif (nbtypes > 0):
|
||||
validate = NameValidator(**validationargs)
|
||||
# Default initial names : should we change the format ?
|
||||
if ((ndtype.names == tuple("f%i" % i for i in range(nbtypes))) and
|
||||
(defaultfmt != "f%i")):
|
||||
ndtype.names = validate([''] * nbtypes, defaultfmt=defaultfmt)
|
||||
# Explicit initial names : just validate
|
||||
else:
|
||||
ndtype.names = validate(ndtype.names, defaultfmt=defaultfmt)
|
||||
return ndtype
|
||||
@@ -0,0 +1,156 @@
|
||||
"""Utility to compare (NumPy) version strings.
|
||||
|
||||
The NumpyVersion class allows properly comparing numpy version strings.
|
||||
The LooseVersion and StrictVersion classes that distutils provides don't
|
||||
work; they don't recognize anything like alpha/beta/rc/dev versions.
|
||||
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import re
|
||||
|
||||
from numpy.compat import basestring
|
||||
|
||||
|
||||
__all__ = ['NumpyVersion']
|
||||
|
||||
|
||||
class NumpyVersion():
|
||||
"""Parse and compare numpy version strings.
|
||||
|
||||
NumPy has the following versioning scheme (numbers given are examples; they
|
||||
can be > 9) in principle):
|
||||
|
||||
- Released version: '1.8.0', '1.8.1', etc.
|
||||
- Alpha: '1.8.0a1', '1.8.0a2', etc.
|
||||
- Beta: '1.8.0b1', '1.8.0b2', etc.
|
||||
- Release candidates: '1.8.0rc1', '1.8.0rc2', etc.
|
||||
- Development versions: '1.8.0.dev-f1234afa' (git commit hash appended)
|
||||
- Development versions after a1: '1.8.0a1.dev-f1234afa',
|
||||
'1.8.0b2.dev-f1234afa',
|
||||
'1.8.1rc1.dev-f1234afa', etc.
|
||||
- Development versions (no git hash available): '1.8.0.dev-Unknown'
|
||||
|
||||
Comparing needs to be done against a valid version string or other
|
||||
`NumpyVersion` instance. Note that all development versions of the same
|
||||
(pre-)release compare equal.
|
||||
|
||||
.. versionadded:: 1.9.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
vstring : str
|
||||
NumPy version string (``np.__version__``).
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from numpy.lib import NumpyVersion
|
||||
>>> if NumpyVersion(np.__version__) < '1.7.0':
|
||||
... print('skip')
|
||||
skip
|
||||
|
||||
>>> NumpyVersion('1.7') # raises ValueError, add ".0"
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, vstring):
|
||||
self.vstring = vstring
|
||||
ver_main = re.match(r'\d[.]\d+[.]\d+', vstring)
|
||||
if not ver_main:
|
||||
raise ValueError("Not a valid numpy version string")
|
||||
|
||||
self.version = ver_main.group()
|
||||
self.major, self.minor, self.bugfix = [int(x) for x in
|
||||
self.version.split('.')]
|
||||
if len(vstring) == ver_main.end():
|
||||
self.pre_release = 'final'
|
||||
else:
|
||||
alpha = re.match(r'a\d', vstring[ver_main.end():])
|
||||
beta = re.match(r'b\d', vstring[ver_main.end():])
|
||||
rc = re.match(r'rc\d', vstring[ver_main.end():])
|
||||
pre_rel = [m for m in [alpha, beta, rc] if m is not None]
|
||||
if pre_rel:
|
||||
self.pre_release = pre_rel[0].group()
|
||||
else:
|
||||
self.pre_release = ''
|
||||
|
||||
self.is_devversion = bool(re.search(r'.dev', vstring))
|
||||
|
||||
def _compare_version(self, other):
|
||||
"""Compare major.minor.bugfix"""
|
||||
if self.major == other.major:
|
||||
if self.minor == other.minor:
|
||||
if self.bugfix == other.bugfix:
|
||||
vercmp = 0
|
||||
elif self.bugfix > other.bugfix:
|
||||
vercmp = 1
|
||||
else:
|
||||
vercmp = -1
|
||||
elif self.minor > other.minor:
|
||||
vercmp = 1
|
||||
else:
|
||||
vercmp = -1
|
||||
elif self.major > other.major:
|
||||
vercmp = 1
|
||||
else:
|
||||
vercmp = -1
|
||||
|
||||
return vercmp
|
||||
|
||||
def _compare_pre_release(self, other):
|
||||
"""Compare alpha/beta/rc/final."""
|
||||
if self.pre_release == other.pre_release:
|
||||
vercmp = 0
|
||||
elif self.pre_release == 'final':
|
||||
vercmp = 1
|
||||
elif other.pre_release == 'final':
|
||||
vercmp = -1
|
||||
elif self.pre_release > other.pre_release:
|
||||
vercmp = 1
|
||||
else:
|
||||
vercmp = -1
|
||||
|
||||
return vercmp
|
||||
|
||||
def _compare(self, other):
|
||||
if not isinstance(other, (basestring, NumpyVersion)):
|
||||
raise ValueError("Invalid object to compare with NumpyVersion.")
|
||||
|
||||
if isinstance(other, basestring):
|
||||
other = NumpyVersion(other)
|
||||
|
||||
vercmp = self._compare_version(other)
|
||||
if vercmp == 0:
|
||||
# Same x.y.z version, check for alpha/beta/rc
|
||||
vercmp = self._compare_pre_release(other)
|
||||
if vercmp == 0:
|
||||
# Same version and same pre-release, check if dev version
|
||||
if self.is_devversion is other.is_devversion:
|
||||
vercmp = 0
|
||||
elif self.is_devversion:
|
||||
vercmp = -1
|
||||
else:
|
||||
vercmp = 1
|
||||
|
||||
return vercmp
|
||||
|
||||
def __lt__(self, other):
|
||||
return self._compare(other) < 0
|
||||
|
||||
def __le__(self, other):
|
||||
return self._compare(other) <= 0
|
||||
|
||||
def __eq__(self, other):
|
||||
return self._compare(other) == 0
|
||||
|
||||
def __ne__(self, other):
|
||||
return self._compare(other) != 0
|
||||
|
||||
def __gt__(self, other):
|
||||
return self._compare(other) > 0
|
||||
|
||||
def __ge__(self, other):
|
||||
return self._compare(other) >= 0
|
||||
|
||||
def __repr(self):
|
||||
return "NumpyVersion(%s)" % self.vstring
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,790 @@
|
||||
"""
|
||||
Set operations for arrays based on sorting.
|
||||
|
||||
:Contains:
|
||||
unique,
|
||||
isin,
|
||||
ediff1d,
|
||||
intersect1d,
|
||||
setxor1d,
|
||||
in1d,
|
||||
union1d,
|
||||
setdiff1d
|
||||
|
||||
:Notes:
|
||||
|
||||
For floating point arrays, inaccurate results may appear due to usual round-off
|
||||
and floating point comparison issues.
|
||||
|
||||
Speed could be gained in some operations by an implementation of
|
||||
sort(), that can provide directly the permutation vectors, avoiding
|
||||
thus calls to argsort().
|
||||
|
||||
To do: Optionally return indices analogously to unique for all functions.
|
||||
|
||||
:Author: Robert Cimrman
|
||||
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import functools
|
||||
|
||||
import numpy as np
|
||||
from numpy.core import overrides
|
||||
|
||||
|
||||
array_function_dispatch = functools.partial(
|
||||
overrides.array_function_dispatch, module='numpy')
|
||||
|
||||
|
||||
__all__ = [
|
||||
'ediff1d', 'intersect1d', 'setxor1d', 'union1d', 'setdiff1d', 'unique',
|
||||
'in1d', 'isin'
|
||||
]
|
||||
|
||||
|
||||
def _ediff1d_dispatcher(ary, to_end=None, to_begin=None):
|
||||
return (ary, to_end, to_begin)
|
||||
|
||||
|
||||
@array_function_dispatch(_ediff1d_dispatcher)
|
||||
def ediff1d(ary, to_end=None, to_begin=None):
|
||||
"""
|
||||
The differences between consecutive elements of an array.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ary : array_like
|
||||
If necessary, will be flattened before the differences are taken.
|
||||
to_end : array_like, optional
|
||||
Number(s) to append at the end of the returned differences.
|
||||
to_begin : array_like, optional
|
||||
Number(s) to prepend at the beginning of the returned differences.
|
||||
|
||||
Returns
|
||||
-------
|
||||
ediff1d : ndarray
|
||||
The differences. Loosely, this is ``ary.flat[1:] - ary.flat[:-1]``.
|
||||
|
||||
See Also
|
||||
--------
|
||||
diff, gradient
|
||||
|
||||
Notes
|
||||
-----
|
||||
When applied to masked arrays, this function drops the mask information
|
||||
if the `to_begin` and/or `to_end` parameters are used.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> x = np.array([1, 2, 4, 7, 0])
|
||||
>>> np.ediff1d(x)
|
||||
array([ 1, 2, 3, -7])
|
||||
|
||||
>>> np.ediff1d(x, to_begin=-99, to_end=np.array([88, 99]))
|
||||
array([-99, 1, 2, 3, -7, 88, 99])
|
||||
|
||||
The returned array is always 1D.
|
||||
|
||||
>>> y = [[1, 2, 4], [1, 6, 24]]
|
||||
>>> np.ediff1d(y)
|
||||
array([ 1, 2, -3, 5, 18])
|
||||
|
||||
"""
|
||||
# force a 1d array
|
||||
ary = np.asanyarray(ary).ravel()
|
||||
|
||||
# we have unit tests enforcing
|
||||
# propagation of the dtype of input
|
||||
# ary to returned result
|
||||
dtype_req = ary.dtype
|
||||
|
||||
# fast track default case
|
||||
if to_begin is None and to_end is None:
|
||||
return ary[1:] - ary[:-1]
|
||||
|
||||
if to_begin is None:
|
||||
l_begin = 0
|
||||
else:
|
||||
to_begin = np.asanyarray(to_begin)
|
||||
if not np.can_cast(to_begin, dtype_req):
|
||||
raise TypeError("dtype of to_begin must be compatible "
|
||||
"with input ary")
|
||||
|
||||
to_begin = to_begin.ravel()
|
||||
l_begin = len(to_begin)
|
||||
|
||||
if to_end is None:
|
||||
l_end = 0
|
||||
else:
|
||||
to_end = np.asanyarray(to_end)
|
||||
if not np.can_cast(to_end, dtype_req):
|
||||
raise TypeError("dtype of to_end must be compatible "
|
||||
"with input ary")
|
||||
|
||||
to_end = to_end.ravel()
|
||||
l_end = len(to_end)
|
||||
|
||||
# do the calculation in place and copy to_begin and to_end
|
||||
l_diff = max(len(ary) - 1, 0)
|
||||
result = np.empty(l_diff + l_begin + l_end, dtype=ary.dtype)
|
||||
result = ary.__array_wrap__(result)
|
||||
if l_begin > 0:
|
||||
result[:l_begin] = to_begin
|
||||
if l_end > 0:
|
||||
result[l_begin + l_diff:] = to_end
|
||||
np.subtract(ary[1:], ary[:-1], result[l_begin:l_begin + l_diff])
|
||||
return result
|
||||
|
||||
|
||||
def _unpack_tuple(x):
|
||||
""" Unpacks one-element tuples for use as return values """
|
||||
if len(x) == 1:
|
||||
return x[0]
|
||||
else:
|
||||
return x
|
||||
|
||||
|
||||
def _unique_dispatcher(ar, return_index=None, return_inverse=None,
|
||||
return_counts=None, axis=None):
|
||||
return (ar,)
|
||||
|
||||
|
||||
@array_function_dispatch(_unique_dispatcher)
|
||||
def unique(ar, return_index=False, return_inverse=False,
|
||||
return_counts=False, axis=None):
|
||||
"""
|
||||
Find the unique elements of an array.
|
||||
|
||||
Returns the sorted unique elements of an array. There are three optional
|
||||
outputs in addition to the unique elements:
|
||||
|
||||
* the indices of the input array that give the unique values
|
||||
* the indices of the unique array that reconstruct the input array
|
||||
* the number of times each unique value comes up in the input array
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ar : array_like
|
||||
Input array. Unless `axis` is specified, this will be flattened if it
|
||||
is not already 1-D.
|
||||
return_index : bool, optional
|
||||
If True, also return the indices of `ar` (along the specified axis,
|
||||
if provided, or in the flattened array) that result in the unique array.
|
||||
return_inverse : bool, optional
|
||||
If True, also return the indices of the unique array (for the specified
|
||||
axis, if provided) that can be used to reconstruct `ar`.
|
||||
return_counts : bool, optional
|
||||
If True, also return the number of times each unique item appears
|
||||
in `ar`.
|
||||
|
||||
.. versionadded:: 1.9.0
|
||||
|
||||
axis : int or None, optional
|
||||
The axis to operate on. If None, `ar` will be flattened. If an integer,
|
||||
the subarrays indexed by the given axis will be flattened and treated
|
||||
as the elements of a 1-D array with the dimension of the given axis,
|
||||
see the notes for more details. Object arrays or structured arrays
|
||||
that contain objects are not supported if the `axis` kwarg is used. The
|
||||
default is None.
|
||||
|
||||
.. versionadded:: 1.13.0
|
||||
|
||||
Returns
|
||||
-------
|
||||
unique : ndarray
|
||||
The sorted unique values.
|
||||
unique_indices : ndarray, optional
|
||||
The indices of the first occurrences of the unique values in the
|
||||
original array. Only provided if `return_index` is True.
|
||||
unique_inverse : ndarray, optional
|
||||
The indices to reconstruct the original array from the
|
||||
unique array. Only provided if `return_inverse` is True.
|
||||
unique_counts : ndarray, optional
|
||||
The number of times each of the unique values comes up in the
|
||||
original array. Only provided if `return_counts` is True.
|
||||
|
||||
.. versionadded:: 1.9.0
|
||||
|
||||
See Also
|
||||
--------
|
||||
numpy.lib.arraysetops : Module with a number of other functions for
|
||||
performing set operations on arrays.
|
||||
|
||||
Notes
|
||||
-----
|
||||
When an axis is specified the subarrays indexed by the axis are sorted.
|
||||
This is done by making the specified axis the first dimension of the array
|
||||
and then flattening the subarrays in C order. The flattened subarrays are
|
||||
then viewed as a structured type with each element given a label, with the
|
||||
effect that we end up with a 1-D array of structured types that can be
|
||||
treated in the same way as any other 1-D array. The result is that the
|
||||
flattened subarrays are sorted in lexicographic order starting with the
|
||||
first element.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.unique([1, 1, 2, 2, 3, 3])
|
||||
array([1, 2, 3])
|
||||
>>> a = np.array([[1, 1], [2, 3]])
|
||||
>>> np.unique(a)
|
||||
array([1, 2, 3])
|
||||
|
||||
Return the unique rows of a 2D array
|
||||
|
||||
>>> a = np.array([[1, 0, 0], [1, 0, 0], [2, 3, 4]])
|
||||
>>> np.unique(a, axis=0)
|
||||
array([[1, 0, 0], [2, 3, 4]])
|
||||
|
||||
Return the indices of the original array that give the unique values:
|
||||
|
||||
>>> a = np.array(['a', 'b', 'b', 'c', 'a'])
|
||||
>>> u, indices = np.unique(a, return_index=True)
|
||||
>>> u
|
||||
array(['a', 'b', 'c'],
|
||||
dtype='|S1')
|
||||
>>> indices
|
||||
array([0, 1, 3])
|
||||
>>> a[indices]
|
||||
array(['a', 'b', 'c'],
|
||||
dtype='|S1')
|
||||
|
||||
Reconstruct the input array from the unique values:
|
||||
|
||||
>>> a = np.array([1, 2, 6, 4, 2, 3, 2])
|
||||
>>> u, indices = np.unique(a, return_inverse=True)
|
||||
>>> u
|
||||
array([1, 2, 3, 4, 6])
|
||||
>>> indices
|
||||
array([0, 1, 4, 3, 1, 2, 1])
|
||||
>>> u[indices]
|
||||
array([1, 2, 6, 4, 2, 3, 2])
|
||||
|
||||
"""
|
||||
ar = np.asanyarray(ar)
|
||||
if axis is None:
|
||||
ret = _unique1d(ar, return_index, return_inverse, return_counts)
|
||||
return _unpack_tuple(ret)
|
||||
|
||||
# axis was specified and not None
|
||||
try:
|
||||
ar = np.swapaxes(ar, axis, 0)
|
||||
except np.AxisError:
|
||||
# this removes the "axis1" or "axis2" prefix from the error message
|
||||
raise np.AxisError(axis, ar.ndim)
|
||||
|
||||
# Must reshape to a contiguous 2D array for this to work...
|
||||
orig_shape, orig_dtype = ar.shape, ar.dtype
|
||||
ar = ar.reshape(orig_shape[0], -1)
|
||||
ar = np.ascontiguousarray(ar)
|
||||
dtype = [('f{i}'.format(i=i), ar.dtype) for i in range(ar.shape[1])]
|
||||
|
||||
try:
|
||||
consolidated = ar.view(dtype)
|
||||
except TypeError:
|
||||
# There's no good way to do this for object arrays, etc...
|
||||
msg = 'The axis argument to unique is not supported for dtype {dt}'
|
||||
raise TypeError(msg.format(dt=ar.dtype))
|
||||
|
||||
def reshape_uniq(uniq):
|
||||
uniq = uniq.view(orig_dtype)
|
||||
uniq = uniq.reshape(-1, *orig_shape[1:])
|
||||
uniq = np.swapaxes(uniq, 0, axis)
|
||||
return uniq
|
||||
|
||||
output = _unique1d(consolidated, return_index,
|
||||
return_inverse, return_counts)
|
||||
output = (reshape_uniq(output[0]),) + output[1:]
|
||||
return _unpack_tuple(output)
|
||||
|
||||
|
||||
def _unique1d(ar, return_index=False, return_inverse=False,
|
||||
return_counts=False):
|
||||
"""
|
||||
Find the unique elements of an array, ignoring shape.
|
||||
"""
|
||||
ar = np.asanyarray(ar).flatten()
|
||||
|
||||
optional_indices = return_index or return_inverse
|
||||
|
||||
if optional_indices:
|
||||
perm = ar.argsort(kind='mergesort' if return_index else 'quicksort')
|
||||
aux = ar[perm]
|
||||
else:
|
||||
ar.sort()
|
||||
aux = ar
|
||||
mask = np.empty(aux.shape, dtype=np.bool_)
|
||||
mask[:1] = True
|
||||
mask[1:] = aux[1:] != aux[:-1]
|
||||
|
||||
ret = (aux[mask],)
|
||||
if return_index:
|
||||
ret += (perm[mask],)
|
||||
if return_inverse:
|
||||
imask = np.cumsum(mask) - 1
|
||||
inv_idx = np.empty(mask.shape, dtype=np.intp)
|
||||
inv_idx[perm] = imask
|
||||
ret += (inv_idx,)
|
||||
if return_counts:
|
||||
idx = np.concatenate(np.nonzero(mask) + ([mask.size],))
|
||||
ret += (np.diff(idx),)
|
||||
return ret
|
||||
|
||||
|
||||
def _intersect1d_dispatcher(
|
||||
ar1, ar2, assume_unique=None, return_indices=None):
|
||||
return (ar1, ar2)
|
||||
|
||||
|
||||
@array_function_dispatch(_intersect1d_dispatcher)
|
||||
def intersect1d(ar1, ar2, assume_unique=False, return_indices=False):
|
||||
"""
|
||||
Find the intersection of two arrays.
|
||||
|
||||
Return the sorted, unique values that are in both of the input arrays.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ar1, ar2 : array_like
|
||||
Input arrays. Will be flattened if not already 1D.
|
||||
assume_unique : bool
|
||||
If True, the input arrays are both assumed to be unique, which
|
||||
can speed up the calculation. Default is False.
|
||||
return_indices : bool
|
||||
If True, the indices which correspond to the intersection of the two
|
||||
arrays are returned. The first instance of a value is used if there are
|
||||
multiple. Default is False.
|
||||
|
||||
.. versionadded:: 1.15.0
|
||||
|
||||
Returns
|
||||
-------
|
||||
intersect1d : ndarray
|
||||
Sorted 1D array of common and unique elements.
|
||||
comm1 : ndarray
|
||||
The indices of the first occurrences of the common values in `ar1`.
|
||||
Only provided if `return_indices` is True.
|
||||
comm2 : ndarray
|
||||
The indices of the first occurrences of the common values in `ar2`.
|
||||
Only provided if `return_indices` is True.
|
||||
|
||||
|
||||
See Also
|
||||
--------
|
||||
numpy.lib.arraysetops : Module with a number of other functions for
|
||||
performing set operations on arrays.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.intersect1d([1, 3, 4, 3], [3, 1, 2, 1])
|
||||
array([1, 3])
|
||||
|
||||
To intersect more than two arrays, use functools.reduce:
|
||||
|
||||
>>> from functools import reduce
|
||||
>>> reduce(np.intersect1d, ([1, 3, 4, 3], [3, 1, 2, 1], [6, 3, 4, 2]))
|
||||
array([3])
|
||||
|
||||
To return the indices of the values common to the input arrays
|
||||
along with the intersected values:
|
||||
>>> x = np.array([1, 1, 2, 3, 4])
|
||||
>>> y = np.array([2, 1, 4, 6])
|
||||
>>> xy, x_ind, y_ind = np.intersect1d(x, y, return_indices=True)
|
||||
>>> x_ind, y_ind
|
||||
(array([0, 2, 4]), array([1, 0, 2]))
|
||||
>>> xy, x[x_ind], y[y_ind]
|
||||
(array([1, 2, 4]), array([1, 2, 4]), array([1, 2, 4]))
|
||||
|
||||
"""
|
||||
ar1 = np.asanyarray(ar1)
|
||||
ar2 = np.asanyarray(ar2)
|
||||
|
||||
if not assume_unique:
|
||||
if return_indices:
|
||||
ar1, ind1 = unique(ar1, return_index=True)
|
||||
ar2, ind2 = unique(ar2, return_index=True)
|
||||
else:
|
||||
ar1 = unique(ar1)
|
||||
ar2 = unique(ar2)
|
||||
else:
|
||||
ar1 = ar1.ravel()
|
||||
ar2 = ar2.ravel()
|
||||
|
||||
aux = np.concatenate((ar1, ar2))
|
||||
if return_indices:
|
||||
aux_sort_indices = np.argsort(aux, kind='mergesort')
|
||||
aux = aux[aux_sort_indices]
|
||||
else:
|
||||
aux.sort()
|
||||
|
||||
mask = aux[1:] == aux[:-1]
|
||||
int1d = aux[:-1][mask]
|
||||
|
||||
if return_indices:
|
||||
ar1_indices = aux_sort_indices[:-1][mask]
|
||||
ar2_indices = aux_sort_indices[1:][mask] - ar1.size
|
||||
if not assume_unique:
|
||||
ar1_indices = ind1[ar1_indices]
|
||||
ar2_indices = ind2[ar2_indices]
|
||||
|
||||
return int1d, ar1_indices, ar2_indices
|
||||
else:
|
||||
return int1d
|
||||
|
||||
|
||||
def _setxor1d_dispatcher(ar1, ar2, assume_unique=None):
|
||||
return (ar1, ar2)
|
||||
|
||||
|
||||
@array_function_dispatch(_setxor1d_dispatcher)
|
||||
def setxor1d(ar1, ar2, assume_unique=False):
|
||||
"""
|
||||
Find the set exclusive-or of two arrays.
|
||||
|
||||
Return the sorted, unique values that are in only one (not both) of the
|
||||
input arrays.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ar1, ar2 : array_like
|
||||
Input arrays.
|
||||
assume_unique : bool
|
||||
If True, the input arrays are both assumed to be unique, which
|
||||
can speed up the calculation. Default is False.
|
||||
|
||||
Returns
|
||||
-------
|
||||
setxor1d : ndarray
|
||||
Sorted 1D array of unique values that are in only one of the input
|
||||
arrays.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> a = np.array([1, 2, 3, 2, 4])
|
||||
>>> b = np.array([2, 3, 5, 7, 5])
|
||||
>>> np.setxor1d(a,b)
|
||||
array([1, 4, 5, 7])
|
||||
|
||||
"""
|
||||
if not assume_unique:
|
||||
ar1 = unique(ar1)
|
||||
ar2 = unique(ar2)
|
||||
|
||||
aux = np.concatenate((ar1, ar2))
|
||||
if aux.size == 0:
|
||||
return aux
|
||||
|
||||
aux.sort()
|
||||
flag = np.concatenate(([True], aux[1:] != aux[:-1], [True]))
|
||||
return aux[flag[1:] & flag[:-1]]
|
||||
|
||||
|
||||
def _in1d_dispatcher(ar1, ar2, assume_unique=None, invert=None):
|
||||
return (ar1, ar2)
|
||||
|
||||
|
||||
@array_function_dispatch(_in1d_dispatcher)
|
||||
def in1d(ar1, ar2, assume_unique=False, invert=False):
|
||||
"""
|
||||
Test whether each element of a 1-D array is also present in a second array.
|
||||
|
||||
Returns a boolean array the same length as `ar1` that is True
|
||||
where an element of `ar1` is in `ar2` and False otherwise.
|
||||
|
||||
We recommend using :func:`isin` instead of `in1d` for new code.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ar1 : (M,) array_like
|
||||
Input array.
|
||||
ar2 : array_like
|
||||
The values against which to test each value of `ar1`.
|
||||
assume_unique : bool, optional
|
||||
If True, the input arrays are both assumed to be unique, which
|
||||
can speed up the calculation. Default is False.
|
||||
invert : bool, optional
|
||||
If True, the values in the returned array are inverted (that is,
|
||||
False where an element of `ar1` is in `ar2` and True otherwise).
|
||||
Default is False. ``np.in1d(a, b, invert=True)`` is equivalent
|
||||
to (but is faster than) ``np.invert(in1d(a, b))``.
|
||||
|
||||
.. versionadded:: 1.8.0
|
||||
|
||||
Returns
|
||||
-------
|
||||
in1d : (M,) ndarray, bool
|
||||
The values `ar1[in1d]` are in `ar2`.
|
||||
|
||||
See Also
|
||||
--------
|
||||
isin : Version of this function that preserves the
|
||||
shape of ar1.
|
||||
numpy.lib.arraysetops : Module with a number of other functions for
|
||||
performing set operations on arrays.
|
||||
|
||||
Notes
|
||||
-----
|
||||
`in1d` can be considered as an element-wise function version of the
|
||||
python keyword `in`, for 1-D sequences. ``in1d(a, b)`` is roughly
|
||||
equivalent to ``np.array([item in b for item in a])``.
|
||||
However, this idea fails if `ar2` is a set, or similar (non-sequence)
|
||||
container: As ``ar2`` is converted to an array, in those cases
|
||||
``asarray(ar2)`` is an object array rather than the expected array of
|
||||
contained values.
|
||||
|
||||
.. versionadded:: 1.4.0
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> test = np.array([0, 1, 2, 5, 0])
|
||||
>>> states = [0, 2]
|
||||
>>> mask = np.in1d(test, states)
|
||||
>>> mask
|
||||
array([ True, False, True, False, True])
|
||||
>>> test[mask]
|
||||
array([0, 2, 0])
|
||||
>>> mask = np.in1d(test, states, invert=True)
|
||||
>>> mask
|
||||
array([False, True, False, True, False])
|
||||
>>> test[mask]
|
||||
array([1, 5])
|
||||
"""
|
||||
# Ravel both arrays, behavior for the first array could be different
|
||||
ar1 = np.asarray(ar1).ravel()
|
||||
ar2 = np.asarray(ar2).ravel()
|
||||
|
||||
# Check if one of the arrays may contain arbitrary objects
|
||||
contains_object = ar1.dtype.hasobject or ar2.dtype.hasobject
|
||||
|
||||
# This code is run when
|
||||
# a) the first condition is true, making the code significantly faster
|
||||
# b) the second condition is true (i.e. `ar1` or `ar2` may contain
|
||||
# arbitrary objects), since then sorting is not guaranteed to work
|
||||
if len(ar2) < 10 * len(ar1) ** 0.145 or contains_object:
|
||||
if invert:
|
||||
mask = np.ones(len(ar1), dtype=bool)
|
||||
for a in ar2:
|
||||
mask &= (ar1 != a)
|
||||
else:
|
||||
mask = np.zeros(len(ar1), dtype=bool)
|
||||
for a in ar2:
|
||||
mask |= (ar1 == a)
|
||||
return mask
|
||||
|
||||
# Otherwise use sorting
|
||||
if not assume_unique:
|
||||
ar1, rev_idx = np.unique(ar1, return_inverse=True)
|
||||
ar2 = np.unique(ar2)
|
||||
|
||||
ar = np.concatenate((ar1, ar2))
|
||||
# We need this to be a stable sort, so always use 'mergesort'
|
||||
# here. The values from the first array should always come before
|
||||
# the values from the second array.
|
||||
order = ar.argsort(kind='mergesort')
|
||||
sar = ar[order]
|
||||
if invert:
|
||||
bool_ar = (sar[1:] != sar[:-1])
|
||||
else:
|
||||
bool_ar = (sar[1:] == sar[:-1])
|
||||
flag = np.concatenate((bool_ar, [invert]))
|
||||
ret = np.empty(ar.shape, dtype=bool)
|
||||
ret[order] = flag
|
||||
|
||||
if assume_unique:
|
||||
return ret[:len(ar1)]
|
||||
else:
|
||||
return ret[rev_idx]
|
||||
|
||||
|
||||
def _isin_dispatcher(element, test_elements, assume_unique=None, invert=None):
|
||||
return (element, test_elements)
|
||||
|
||||
|
||||
@array_function_dispatch(_isin_dispatcher)
|
||||
def isin(element, test_elements, assume_unique=False, invert=False):
|
||||
"""
|
||||
Calculates `element in test_elements`, broadcasting over `element` only.
|
||||
Returns a boolean array of the same shape as `element` that is True
|
||||
where an element of `element` is in `test_elements` and False otherwise.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
element : array_like
|
||||
Input array.
|
||||
test_elements : array_like
|
||||
The values against which to test each value of `element`.
|
||||
This argument is flattened if it is an array or array_like.
|
||||
See notes for behavior with non-array-like parameters.
|
||||
assume_unique : bool, optional
|
||||
If True, the input arrays are both assumed to be unique, which
|
||||
can speed up the calculation. Default is False.
|
||||
invert : bool, optional
|
||||
If True, the values in the returned array are inverted, as if
|
||||
calculating `element not in test_elements`. Default is False.
|
||||
``np.isin(a, b, invert=True)`` is equivalent to (but faster
|
||||
than) ``np.invert(np.isin(a, b))``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
isin : ndarray, bool
|
||||
Has the same shape as `element`. The values `element[isin]`
|
||||
are in `test_elements`.
|
||||
|
||||
See Also
|
||||
--------
|
||||
in1d : Flattened version of this function.
|
||||
numpy.lib.arraysetops : Module with a number of other functions for
|
||||
performing set operations on arrays.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
`isin` is an element-wise function version of the python keyword `in`.
|
||||
``isin(a, b)`` is roughly equivalent to
|
||||
``np.array([item in b for item in a])`` if `a` and `b` are 1-D sequences.
|
||||
|
||||
`element` and `test_elements` are converted to arrays if they are not
|
||||
already. If `test_elements` is a set (or other non-sequence collection)
|
||||
it will be converted to an object array with one element, rather than an
|
||||
array of the values contained in `test_elements`. This is a consequence
|
||||
of the `array` constructor's way of handling non-sequence collections.
|
||||
Converting the set to a list usually gives the desired behavior.
|
||||
|
||||
.. versionadded:: 1.13.0
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> element = 2*np.arange(4).reshape((2, 2))
|
||||
>>> element
|
||||
array([[0, 2],
|
||||
[4, 6]])
|
||||
>>> test_elements = [1, 2, 4, 8]
|
||||
>>> mask = np.isin(element, test_elements)
|
||||
>>> mask
|
||||
array([[ False, True],
|
||||
[ True, False]])
|
||||
>>> element[mask]
|
||||
array([2, 4])
|
||||
|
||||
The indices of the matched values can be obtained with `nonzero`:
|
||||
|
||||
>>> np.nonzero(mask)
|
||||
(array([0, 1]), array([1, 0]))
|
||||
|
||||
The test can also be inverted:
|
||||
|
||||
>>> mask = np.isin(element, test_elements, invert=True)
|
||||
>>> mask
|
||||
array([[ True, False],
|
||||
[ False, True]])
|
||||
>>> element[mask]
|
||||
array([0, 6])
|
||||
|
||||
Because of how `array` handles sets, the following does not
|
||||
work as expected:
|
||||
|
||||
>>> test_set = {1, 2, 4, 8}
|
||||
>>> np.isin(element, test_set)
|
||||
array([[ False, False],
|
||||
[ False, False]])
|
||||
|
||||
Casting the set to a list gives the expected result:
|
||||
|
||||
>>> np.isin(element, list(test_set))
|
||||
array([[ False, True],
|
||||
[ True, False]])
|
||||
"""
|
||||
element = np.asarray(element)
|
||||
return in1d(element, test_elements, assume_unique=assume_unique,
|
||||
invert=invert).reshape(element.shape)
|
||||
|
||||
|
||||
def _union1d_dispatcher(ar1, ar2):
|
||||
return (ar1, ar2)
|
||||
|
||||
|
||||
@array_function_dispatch(_union1d_dispatcher)
|
||||
def union1d(ar1, ar2):
|
||||
"""
|
||||
Find the union of two arrays.
|
||||
|
||||
Return the unique, sorted array of values that are in either of the two
|
||||
input arrays.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ar1, ar2 : array_like
|
||||
Input arrays. They are flattened if they are not already 1D.
|
||||
|
||||
Returns
|
||||
-------
|
||||
union1d : ndarray
|
||||
Unique, sorted union of the input arrays.
|
||||
|
||||
See Also
|
||||
--------
|
||||
numpy.lib.arraysetops : Module with a number of other functions for
|
||||
performing set operations on arrays.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.union1d([-1, 0, 1], [-2, 0, 2])
|
||||
array([-2, -1, 0, 1, 2])
|
||||
|
||||
To find the union of more than two arrays, use functools.reduce:
|
||||
|
||||
>>> from functools import reduce
|
||||
>>> reduce(np.union1d, ([1, 3, 4, 3], [3, 1, 2, 1], [6, 3, 4, 2]))
|
||||
array([1, 2, 3, 4, 6])
|
||||
"""
|
||||
return unique(np.concatenate((ar1, ar2), axis=None))
|
||||
|
||||
|
||||
def _setdiff1d_dispatcher(ar1, ar2, assume_unique=None):
|
||||
return (ar1, ar2)
|
||||
|
||||
|
||||
@array_function_dispatch(_setdiff1d_dispatcher)
|
||||
def setdiff1d(ar1, ar2, assume_unique=False):
|
||||
"""
|
||||
Find the set difference of two arrays.
|
||||
|
||||
Return the unique values in `ar1` that are not in `ar2`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ar1 : array_like
|
||||
Input array.
|
||||
ar2 : array_like
|
||||
Input comparison array.
|
||||
assume_unique : bool
|
||||
If True, the input arrays are both assumed to be unique, which
|
||||
can speed up the calculation. Default is False.
|
||||
|
||||
Returns
|
||||
-------
|
||||
setdiff1d : ndarray
|
||||
1D array of values in `ar1` that are not in `ar2`. The result
|
||||
is sorted when `assume_unique=False`, but otherwise only sorted
|
||||
if the input is sorted.
|
||||
|
||||
See Also
|
||||
--------
|
||||
numpy.lib.arraysetops : Module with a number of other functions for
|
||||
performing set operations on arrays.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> a = np.array([1, 2, 3, 2, 4, 1])
|
||||
>>> b = np.array([3, 4, 5, 6])
|
||||
>>> np.setdiff1d(a, b)
|
||||
array([1, 2])
|
||||
|
||||
"""
|
||||
if assume_unique:
|
||||
ar1 = np.asarray(ar1).ravel()
|
||||
else:
|
||||
ar1 = unique(ar1)
|
||||
ar2 = unique(ar2)
|
||||
return ar1[in1d(ar1, ar2, assume_unique=True, invert=True)]
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
"""
|
||||
A buffered iterator for big arrays.
|
||||
|
||||
This module solves the problem of iterating over a big file-based array
|
||||
without having to read it into memory. The `Arrayterator` class wraps
|
||||
an array object, and when iterated it will return sub-arrays with at most
|
||||
a user-specified number of elements.
|
||||
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
from operator import mul
|
||||
from functools import reduce
|
||||
|
||||
from numpy.compat import long
|
||||
|
||||
__all__ = ['Arrayterator']
|
||||
|
||||
|
||||
class Arrayterator(object):
|
||||
"""
|
||||
Buffered iterator for big arrays.
|
||||
|
||||
`Arrayterator` creates a buffered iterator for reading big arrays in small
|
||||
contiguous blocks. The class is useful for objects stored in the
|
||||
file system. It allows iteration over the object *without* reading
|
||||
everything in memory; instead, small blocks are read and iterated over.
|
||||
|
||||
`Arrayterator` can be used with any object that supports multidimensional
|
||||
slices. This includes NumPy arrays, but also variables from
|
||||
Scientific.IO.NetCDF or pynetcdf for example.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
var : array_like
|
||||
The object to iterate over.
|
||||
buf_size : int, optional
|
||||
The buffer size. If `buf_size` is supplied, the maximum amount of
|
||||
data that will be read into memory is `buf_size` elements.
|
||||
Default is None, which will read as many element as possible
|
||||
into memory.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
var
|
||||
buf_size
|
||||
start
|
||||
stop
|
||||
step
|
||||
shape
|
||||
flat
|
||||
|
||||
See Also
|
||||
--------
|
||||
ndenumerate : Multidimensional array iterator.
|
||||
flatiter : Flat array iterator.
|
||||
memmap : Create a memory-map to an array stored in a binary file on disk.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The algorithm works by first finding a "running dimension", along which
|
||||
the blocks will be extracted. Given an array of dimensions
|
||||
``(d1, d2, ..., dn)``, e.g. if `buf_size` is smaller than ``d1``, the
|
||||
first dimension will be used. If, on the other hand,
|
||||
``d1 < buf_size < d1*d2`` the second dimension will be used, and so on.
|
||||
Blocks are extracted along this dimension, and when the last block is
|
||||
returned the process continues from the next dimension, until all
|
||||
elements have been read.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> a = np.arange(3 * 4 * 5 * 6).reshape(3, 4, 5, 6)
|
||||
>>> a_itor = np.lib.Arrayterator(a, 2)
|
||||
>>> a_itor.shape
|
||||
(3, 4, 5, 6)
|
||||
|
||||
Now we can iterate over ``a_itor``, and it will return arrays of size
|
||||
two. Since `buf_size` was smaller than any dimension, the first
|
||||
dimension will be iterated over first:
|
||||
|
||||
>>> for subarr in a_itor:
|
||||
... if not subarr.all():
|
||||
... print(subarr, subarr.shape)
|
||||
...
|
||||
[[[[0 1]]]] (1, 1, 1, 2)
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, var, buf_size=None):
|
||||
self.var = var
|
||||
self.buf_size = buf_size
|
||||
|
||||
self.start = [0 for dim in var.shape]
|
||||
self.stop = [dim for dim in var.shape]
|
||||
self.step = [1 for dim in var.shape]
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.var, attr)
|
||||
|
||||
def __getitem__(self, index):
|
||||
"""
|
||||
Return a new arrayterator.
|
||||
|
||||
"""
|
||||
# Fix index, handling ellipsis and incomplete slices.
|
||||
if not isinstance(index, tuple):
|
||||
index = (index,)
|
||||
fixed = []
|
||||
length, dims = len(index), self.ndim
|
||||
for slice_ in index:
|
||||
if slice_ is Ellipsis:
|
||||
fixed.extend([slice(None)] * (dims-length+1))
|
||||
length = len(fixed)
|
||||
elif isinstance(slice_, (int, long)):
|
||||
fixed.append(slice(slice_, slice_+1, 1))
|
||||
else:
|
||||
fixed.append(slice_)
|
||||
index = tuple(fixed)
|
||||
if len(index) < dims:
|
||||
index += (slice(None),) * (dims-len(index))
|
||||
|
||||
# Return a new arrayterator object.
|
||||
out = self.__class__(self.var, self.buf_size)
|
||||
for i, (start, stop, step, slice_) in enumerate(
|
||||
zip(self.start, self.stop, self.step, index)):
|
||||
out.start[i] = start + (slice_.start or 0)
|
||||
out.step[i] = step * (slice_.step or 1)
|
||||
out.stop[i] = start + (slice_.stop or stop-start)
|
||||
out.stop[i] = min(stop, out.stop[i])
|
||||
return out
|
||||
|
||||
def __array__(self):
|
||||
"""
|
||||
Return corresponding data.
|
||||
|
||||
"""
|
||||
slice_ = tuple(slice(*t) for t in zip(
|
||||
self.start, self.stop, self.step))
|
||||
return self.var[slice_]
|
||||
|
||||
@property
|
||||
def flat(self):
|
||||
"""
|
||||
A 1-D flat iterator for Arrayterator objects.
|
||||
|
||||
This iterator returns elements of the array to be iterated over in
|
||||
`Arrayterator` one by one. It is similar to `flatiter`.
|
||||
|
||||
See Also
|
||||
--------
|
||||
Arrayterator
|
||||
flatiter
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> a = np.arange(3 * 4 * 5 * 6).reshape(3, 4, 5, 6)
|
||||
>>> a_itor = np.lib.Arrayterator(a, 2)
|
||||
|
||||
>>> for subarr in a_itor.flat:
|
||||
... if not subarr:
|
||||
... print(subarr, type(subarr))
|
||||
...
|
||||
0 <type 'numpy.int32'>
|
||||
|
||||
"""
|
||||
for block in self:
|
||||
for value in block.flat:
|
||||
yield value
|
||||
|
||||
@property
|
||||
def shape(self):
|
||||
"""
|
||||
The shape of the array to be iterated over.
|
||||
|
||||
For an example, see `Arrayterator`.
|
||||
|
||||
"""
|
||||
return tuple(((stop-start-1)//step+1) for start, stop, step in
|
||||
zip(self.start, self.stop, self.step))
|
||||
|
||||
def __iter__(self):
|
||||
# Skip arrays with degenerate dimensions
|
||||
if [dim for dim in self.shape if dim <= 0]:
|
||||
return
|
||||
|
||||
start = self.start[:]
|
||||
stop = self.stop[:]
|
||||
step = self.step[:]
|
||||
ndims = self.var.ndim
|
||||
|
||||
while True:
|
||||
count = self.buf_size or reduce(mul, self.shape)
|
||||
|
||||
# iterate over each dimension, looking for the
|
||||
# running dimension (ie, the dimension along which
|
||||
# the blocks will be built from)
|
||||
rundim = 0
|
||||
for i in range(ndims-1, -1, -1):
|
||||
# if count is zero we ran out of elements to read
|
||||
# along higher dimensions, so we read only a single position
|
||||
if count == 0:
|
||||
stop[i] = start[i]+1
|
||||
elif count <= self.shape[i]:
|
||||
# limit along this dimension
|
||||
stop[i] = start[i] + count*step[i]
|
||||
rundim = i
|
||||
else:
|
||||
# read everything along this dimension
|
||||
stop[i] = self.stop[i]
|
||||
stop[i] = min(self.stop[i], stop[i])
|
||||
count = count//self.shape[i]
|
||||
|
||||
# yield a block
|
||||
slice_ = tuple(slice(*t) for t in zip(start, stop, step))
|
||||
yield self.var[slice_]
|
||||
|
||||
# Update start position, taking care of overflow to
|
||||
# other dimensions
|
||||
start[rundim] = stop[rundim] # start where we stopped
|
||||
for i in range(ndims-1, 0, -1):
|
||||
if start[i] >= self.stop[i]:
|
||||
start[i] = self.start[i]
|
||||
start[i-1] += self.step[i-1]
|
||||
if start[0] >= self.stop[0]:
|
||||
return
|
||||
@@ -0,0 +1,830 @@
|
||||
"""Some simple financial calculations
|
||||
|
||||
patterned after spreadsheet computations.
|
||||
|
||||
There is some complexity in each function
|
||||
so that the functions behave like ufuncs with
|
||||
broadcasting and being able to be called with scalars
|
||||
or arrays (or other sequences).
|
||||
|
||||
Functions support the :class:`decimal.Decimal` type unless
|
||||
otherwise stated.
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
from decimal import Decimal
|
||||
import functools
|
||||
|
||||
import numpy as np
|
||||
from numpy.core import overrides
|
||||
|
||||
|
||||
array_function_dispatch = functools.partial(
|
||||
overrides.array_function_dispatch, module='numpy')
|
||||
|
||||
|
||||
__all__ = ['fv', 'pmt', 'nper', 'ipmt', 'ppmt', 'pv', 'rate',
|
||||
'irr', 'npv', 'mirr']
|
||||
|
||||
_when_to_num = {'end':0, 'begin':1,
|
||||
'e':0, 'b':1,
|
||||
0:0, 1:1,
|
||||
'beginning':1,
|
||||
'start':1,
|
||||
'finish':0}
|
||||
|
||||
def _convert_when(when):
|
||||
#Test to see if when has already been converted to ndarray
|
||||
#This will happen if one function calls another, for example ppmt
|
||||
if isinstance(when, np.ndarray):
|
||||
return when
|
||||
try:
|
||||
return _when_to_num[when]
|
||||
except (KeyError, TypeError):
|
||||
return [_when_to_num[x] for x in when]
|
||||
|
||||
|
||||
def _fv_dispatcher(rate, nper, pmt, pv, when=None):
|
||||
return (rate, nper, pmt, pv)
|
||||
|
||||
|
||||
@array_function_dispatch(_fv_dispatcher)
|
||||
def fv(rate, nper, pmt, pv, when='end'):
|
||||
"""
|
||||
Compute the future value.
|
||||
|
||||
Given:
|
||||
* a present value, `pv`
|
||||
* an interest `rate` compounded once per period, of which
|
||||
there are
|
||||
* `nper` total
|
||||
* a (fixed) payment, `pmt`, paid either
|
||||
* at the beginning (`when` = {'begin', 1}) or the end
|
||||
(`when` = {'end', 0}) of each period
|
||||
|
||||
Return:
|
||||
the value at the end of the `nper` periods
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rate : scalar or array_like of shape(M, )
|
||||
Rate of interest as decimal (not per cent) per period
|
||||
nper : scalar or array_like of shape(M, )
|
||||
Number of compounding periods
|
||||
pmt : scalar or array_like of shape(M, )
|
||||
Payment
|
||||
pv : scalar or array_like of shape(M, )
|
||||
Present value
|
||||
when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
|
||||
When payments are due ('begin' (1) or 'end' (0)).
|
||||
Defaults to {'end', 0}.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
Future values. If all input is scalar, returns a scalar float. If
|
||||
any input is array_like, returns future values for each input element.
|
||||
If multiple inputs are array_like, they all must have the same shape.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The future value is computed by solving the equation::
|
||||
|
||||
fv +
|
||||
pv*(1+rate)**nper +
|
||||
pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) == 0
|
||||
|
||||
or, when ``rate == 0``::
|
||||
|
||||
fv + pv + pmt * nper == 0
|
||||
|
||||
References
|
||||
----------
|
||||
.. [WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
|
||||
Open Document Format for Office Applications (OpenDocument)v1.2,
|
||||
Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
|
||||
Pre-Draft 12. Organization for the Advancement of Structured Information
|
||||
Standards (OASIS). Billerica, MA, USA. [ODT Document].
|
||||
Available:
|
||||
http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
|
||||
OpenDocument-formula-20090508.odt
|
||||
|
||||
Examples
|
||||
--------
|
||||
What is the future value after 10 years of saving $100 now, with
|
||||
an additional monthly savings of $100. Assume the interest rate is
|
||||
5% (annually) compounded monthly?
|
||||
|
||||
>>> np.fv(0.05/12, 10*12, -100, -100)
|
||||
15692.928894335748
|
||||
|
||||
By convention, the negative sign represents cash flow out (i.e. money not
|
||||
available today). Thus, saving $100 a month at 5% annual interest leads
|
||||
to $15,692.93 available to spend in 10 years.
|
||||
|
||||
If any input is array_like, returns an array of equal shape. Let's
|
||||
compare different interest rates from the example above.
|
||||
|
||||
>>> a = np.array((0.05, 0.06, 0.07))/12
|
||||
>>> np.fv(a, 10*12, -100, -100)
|
||||
array([ 15692.92889434, 16569.87435405, 17509.44688102])
|
||||
|
||||
"""
|
||||
when = _convert_when(when)
|
||||
(rate, nper, pmt, pv, when) = map(np.asarray, [rate, nper, pmt, pv, when])
|
||||
temp = (1+rate)**nper
|
||||
fact = np.where(rate == 0, nper,
|
||||
(1 + rate*when)*(temp - 1)/rate)
|
||||
return -(pv*temp + pmt*fact)
|
||||
|
||||
|
||||
def _pmt_dispatcher(rate, nper, pv, fv=None, when=None):
|
||||
return (rate, nper, pv, fv)
|
||||
|
||||
|
||||
@array_function_dispatch(_pmt_dispatcher)
|
||||
def pmt(rate, nper, pv, fv=0, when='end'):
|
||||
"""
|
||||
Compute the payment against loan principal plus interest.
|
||||
|
||||
Given:
|
||||
* a present value, `pv` (e.g., an amount borrowed)
|
||||
* a future value, `fv` (e.g., 0)
|
||||
* an interest `rate` compounded once per period, of which
|
||||
there are
|
||||
* `nper` total
|
||||
* and (optional) specification of whether payment is made
|
||||
at the beginning (`when` = {'begin', 1}) or the end
|
||||
(`when` = {'end', 0}) of each period
|
||||
|
||||
Return:
|
||||
the (fixed) periodic payment.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rate : array_like
|
||||
Rate of interest (per period)
|
||||
nper : array_like
|
||||
Number of compounding periods
|
||||
pv : array_like
|
||||
Present value
|
||||
fv : array_like, optional
|
||||
Future value (default = 0)
|
||||
when : {{'begin', 1}, {'end', 0}}, {string, int}
|
||||
When payments are due ('begin' (1) or 'end' (0))
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
Payment against loan plus interest. If all input is scalar, returns a
|
||||
scalar float. If any input is array_like, returns payment for each
|
||||
input element. If multiple inputs are array_like, they all must have
|
||||
the same shape.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The payment is computed by solving the equation::
|
||||
|
||||
fv +
|
||||
pv*(1 + rate)**nper +
|
||||
pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) == 0
|
||||
|
||||
or, when ``rate == 0``::
|
||||
|
||||
fv + pv + pmt * nper == 0
|
||||
|
||||
for ``pmt``.
|
||||
|
||||
Note that computing a monthly mortgage payment is only
|
||||
one use for this function. For example, pmt returns the
|
||||
periodic deposit one must make to achieve a specified
|
||||
future balance given an initial deposit, a fixed,
|
||||
periodically compounded interest rate, and the total
|
||||
number of periods.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
|
||||
Open Document Format for Office Applications (OpenDocument)v1.2,
|
||||
Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
|
||||
Pre-Draft 12. Organization for the Advancement of Structured Information
|
||||
Standards (OASIS). Billerica, MA, USA. [ODT Document].
|
||||
Available:
|
||||
http://www.oasis-open.org/committees/documents.php
|
||||
?wg_abbrev=office-formulaOpenDocument-formula-20090508.odt
|
||||
|
||||
Examples
|
||||
--------
|
||||
What is the monthly payment needed to pay off a $200,000 loan in 15
|
||||
years at an annual interest rate of 7.5%?
|
||||
|
||||
>>> np.pmt(0.075/12, 12*15, 200000)
|
||||
-1854.0247200054619
|
||||
|
||||
In order to pay-off (i.e., have a future-value of 0) the $200,000 obtained
|
||||
today, a monthly payment of $1,854.02 would be required. Note that this
|
||||
example illustrates usage of `fv` having a default value of 0.
|
||||
|
||||
"""
|
||||
when = _convert_when(when)
|
||||
(rate, nper, pv, fv, when) = map(np.array, [rate, nper, pv, fv, when])
|
||||
temp = (1 + rate)**nper
|
||||
mask = (rate == 0)
|
||||
masked_rate = np.where(mask, 1, rate)
|
||||
fact = np.where(mask != 0, nper,
|
||||
(1 + masked_rate*when)*(temp - 1)/masked_rate)
|
||||
return -(fv + pv*temp) / fact
|
||||
|
||||
|
||||
def _nper_dispatcher(rate, pmt, pv, fv=None, when=None):
|
||||
return (rate, pmt, pv, fv)
|
||||
|
||||
|
||||
@array_function_dispatch(_nper_dispatcher)
|
||||
def nper(rate, pmt, pv, fv=0, when='end'):
|
||||
"""
|
||||
Compute the number of periodic payments.
|
||||
|
||||
:class:`decimal.Decimal` type is not supported.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rate : array_like
|
||||
Rate of interest (per period)
|
||||
pmt : array_like
|
||||
Payment
|
||||
pv : array_like
|
||||
Present value
|
||||
fv : array_like, optional
|
||||
Future value
|
||||
when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
|
||||
When payments are due ('begin' (1) or 'end' (0))
|
||||
|
||||
Notes
|
||||
-----
|
||||
The number of periods ``nper`` is computed by solving the equation::
|
||||
|
||||
fv + pv*(1+rate)**nper + pmt*(1+rate*when)/rate*((1+rate)**nper-1) = 0
|
||||
|
||||
but if ``rate = 0`` then::
|
||||
|
||||
fv + pv + pmt*nper = 0
|
||||
|
||||
Examples
|
||||
--------
|
||||
If you only had $150/month to pay towards the loan, how long would it take
|
||||
to pay-off a loan of $8,000 at 7% annual interest?
|
||||
|
||||
>>> print(round(np.nper(0.07/12, -150, 8000), 5))
|
||||
64.07335
|
||||
|
||||
So, over 64 months would be required to pay off the loan.
|
||||
|
||||
The same analysis could be done with several different interest rates
|
||||
and/or payments and/or total amounts to produce an entire table.
|
||||
|
||||
>>> np.nper(*(np.ogrid[0.07/12: 0.08/12: 0.01/12,
|
||||
... -150 : -99 : 50 ,
|
||||
... 8000 : 9001 : 1000]))
|
||||
array([[[ 64.07334877, 74.06368256],
|
||||
[ 108.07548412, 127.99022654]],
|
||||
[[ 66.12443902, 76.87897353],
|
||||
[ 114.70165583, 137.90124779]]])
|
||||
|
||||
"""
|
||||
when = _convert_when(when)
|
||||
(rate, pmt, pv, fv, when) = map(np.asarray, [rate, pmt, pv, fv, when])
|
||||
|
||||
use_zero_rate = False
|
||||
with np.errstate(divide="raise"):
|
||||
try:
|
||||
z = pmt*(1+rate*when)/rate
|
||||
except FloatingPointError:
|
||||
use_zero_rate = True
|
||||
|
||||
if use_zero_rate:
|
||||
return (-fv + pv) / pmt
|
||||
else:
|
||||
A = -(fv + pv)/(pmt+0)
|
||||
B = np.log((-fv+z) / (pv+z))/np.log(1+rate)
|
||||
return np.where(rate == 0, A, B)
|
||||
|
||||
|
||||
def _ipmt_dispatcher(rate, per, nper, pv, fv=None, when=None):
|
||||
return (rate, per, nper, pv, fv)
|
||||
|
||||
|
||||
@array_function_dispatch(_ipmt_dispatcher)
|
||||
def ipmt(rate, per, nper, pv, fv=0, when='end'):
|
||||
"""
|
||||
Compute the interest portion of a payment.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rate : scalar or array_like of shape(M, )
|
||||
Rate of interest as decimal (not per cent) per period
|
||||
per : scalar or array_like of shape(M, )
|
||||
Interest paid against the loan changes during the life or the loan.
|
||||
The `per` is the payment period to calculate the interest amount.
|
||||
nper : scalar or array_like of shape(M, )
|
||||
Number of compounding periods
|
||||
pv : scalar or array_like of shape(M, )
|
||||
Present value
|
||||
fv : scalar or array_like of shape(M, ), optional
|
||||
Future value
|
||||
when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
|
||||
When payments are due ('begin' (1) or 'end' (0)).
|
||||
Defaults to {'end', 0}.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
Interest portion of payment. If all input is scalar, returns a scalar
|
||||
float. If any input is array_like, returns interest payment for each
|
||||
input element. If multiple inputs are array_like, they all must have
|
||||
the same shape.
|
||||
|
||||
See Also
|
||||
--------
|
||||
ppmt, pmt, pv
|
||||
|
||||
Notes
|
||||
-----
|
||||
The total payment is made up of payment against principal plus interest.
|
||||
|
||||
``pmt = ppmt + ipmt``
|
||||
|
||||
Examples
|
||||
--------
|
||||
What is the amortization schedule for a 1 year loan of $2500 at
|
||||
8.24% interest per year compounded monthly?
|
||||
|
||||
>>> principal = 2500.00
|
||||
|
||||
The 'per' variable represents the periods of the loan. Remember that
|
||||
financial equations start the period count at 1!
|
||||
|
||||
>>> per = np.arange(1*12) + 1
|
||||
>>> ipmt = np.ipmt(0.0824/12, per, 1*12, principal)
|
||||
>>> ppmt = np.ppmt(0.0824/12, per, 1*12, principal)
|
||||
|
||||
Each element of the sum of the 'ipmt' and 'ppmt' arrays should equal
|
||||
'pmt'.
|
||||
|
||||
>>> pmt = np.pmt(0.0824/12, 1*12, principal)
|
||||
>>> np.allclose(ipmt + ppmt, pmt)
|
||||
True
|
||||
|
||||
>>> fmt = '{0:2d} {1:8.2f} {2:8.2f} {3:8.2f}'
|
||||
>>> for payment in per:
|
||||
... index = payment - 1
|
||||
... principal = principal + ppmt[index]
|
||||
... print(fmt.format(payment, ppmt[index], ipmt[index], principal))
|
||||
1 -200.58 -17.17 2299.42
|
||||
2 -201.96 -15.79 2097.46
|
||||
3 -203.35 -14.40 1894.11
|
||||
4 -204.74 -13.01 1689.37
|
||||
5 -206.15 -11.60 1483.22
|
||||
6 -207.56 -10.18 1275.66
|
||||
7 -208.99 -8.76 1066.67
|
||||
8 -210.42 -7.32 856.25
|
||||
9 -211.87 -5.88 644.38
|
||||
10 -213.32 -4.42 431.05
|
||||
11 -214.79 -2.96 216.26
|
||||
12 -216.26 -1.49 -0.00
|
||||
|
||||
>>> interestpd = np.sum(ipmt)
|
||||
>>> np.round(interestpd, 2)
|
||||
-112.98
|
||||
|
||||
"""
|
||||
when = _convert_when(when)
|
||||
rate, per, nper, pv, fv, when = np.broadcast_arrays(rate, per, nper,
|
||||
pv, fv, when)
|
||||
total_pmt = pmt(rate, nper, pv, fv, when)
|
||||
ipmt = _rbl(rate, per, total_pmt, pv, when)*rate
|
||||
try:
|
||||
ipmt = np.where(when == 1, ipmt/(1 + rate), ipmt)
|
||||
ipmt = np.where(np.logical_and(when == 1, per == 1), 0, ipmt)
|
||||
except IndexError:
|
||||
pass
|
||||
return ipmt
|
||||
|
||||
|
||||
def _rbl(rate, per, pmt, pv, when):
|
||||
"""
|
||||
This function is here to simply have a different name for the 'fv'
|
||||
function to not interfere with the 'fv' keyword argument within the 'ipmt'
|
||||
function. It is the 'remaining balance on loan' which might be useful as
|
||||
it's own function, but is easily calculated with the 'fv' function.
|
||||
"""
|
||||
return fv(rate, (per - 1), pmt, pv, when)
|
||||
|
||||
|
||||
def _ppmt_dispatcher(rate, per, nper, pv, fv=None, when=None):
|
||||
return (rate, per, nper, pv, fv)
|
||||
|
||||
|
||||
@array_function_dispatch(_ppmt_dispatcher)
|
||||
def ppmt(rate, per, nper, pv, fv=0, when='end'):
|
||||
"""
|
||||
Compute the payment against loan principal.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rate : array_like
|
||||
Rate of interest (per period)
|
||||
per : array_like, int
|
||||
Amount paid against the loan changes. The `per` is the period of
|
||||
interest.
|
||||
nper : array_like
|
||||
Number of compounding periods
|
||||
pv : array_like
|
||||
Present value
|
||||
fv : array_like, optional
|
||||
Future value
|
||||
when : {{'begin', 1}, {'end', 0}}, {string, int}
|
||||
When payments are due ('begin' (1) or 'end' (0))
|
||||
|
||||
See Also
|
||||
--------
|
||||
pmt, pv, ipmt
|
||||
|
||||
"""
|
||||
total = pmt(rate, nper, pv, fv, when)
|
||||
return total - ipmt(rate, per, nper, pv, fv, when)
|
||||
|
||||
|
||||
def _pv_dispatcher(rate, nper, pmt, fv=None, when=None):
|
||||
return (rate, nper, nper, pv, fv)
|
||||
|
||||
|
||||
@array_function_dispatch(_pv_dispatcher)
|
||||
def pv(rate, nper, pmt, fv=0, when='end'):
|
||||
"""
|
||||
Compute the present value.
|
||||
|
||||
Given:
|
||||
* a future value, `fv`
|
||||
* an interest `rate` compounded once per period, of which
|
||||
there are
|
||||
* `nper` total
|
||||
* a (fixed) payment, `pmt`, paid either
|
||||
* at the beginning (`when` = {'begin', 1}) or the end
|
||||
(`when` = {'end', 0}) of each period
|
||||
|
||||
Return:
|
||||
the value now
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rate : array_like
|
||||
Rate of interest (per period)
|
||||
nper : array_like
|
||||
Number of compounding periods
|
||||
pmt : array_like
|
||||
Payment
|
||||
fv : array_like, optional
|
||||
Future value
|
||||
when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
|
||||
When payments are due ('begin' (1) or 'end' (0))
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray, float
|
||||
Present value of a series of payments or investments.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The present value is computed by solving the equation::
|
||||
|
||||
fv +
|
||||
pv*(1 + rate)**nper +
|
||||
pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) = 0
|
||||
|
||||
or, when ``rate = 0``::
|
||||
|
||||
fv + pv + pmt * nper = 0
|
||||
|
||||
for `pv`, which is then returned.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
|
||||
Open Document Format for Office Applications (OpenDocument)v1.2,
|
||||
Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
|
||||
Pre-Draft 12. Organization for the Advancement of Structured Information
|
||||
Standards (OASIS). Billerica, MA, USA. [ODT Document].
|
||||
Available:
|
||||
http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
|
||||
OpenDocument-formula-20090508.odt
|
||||
|
||||
Examples
|
||||
--------
|
||||
What is the present value (e.g., the initial investment)
|
||||
of an investment that needs to total $15692.93
|
||||
after 10 years of saving $100 every month? Assume the
|
||||
interest rate is 5% (annually) compounded monthly.
|
||||
|
||||
>>> np.pv(0.05/12, 10*12, -100, 15692.93)
|
||||
-100.00067131625819
|
||||
|
||||
By convention, the negative sign represents cash flow out
|
||||
(i.e., money not available today). Thus, to end up with
|
||||
$15,692.93 in 10 years saving $100 a month at 5% annual
|
||||
interest, one's initial deposit should also be $100.
|
||||
|
||||
If any input is array_like, ``pv`` returns an array of equal shape.
|
||||
Let's compare different interest rates in the example above:
|
||||
|
||||
>>> a = np.array((0.05, 0.04, 0.03))/12
|
||||
>>> np.pv(a, 10*12, -100, 15692.93)
|
||||
array([ -100.00067132, -649.26771385, -1273.78633713])
|
||||
|
||||
So, to end up with the same $15692.93 under the same $100 per month
|
||||
"savings plan," for annual interest rates of 4% and 3%, one would
|
||||
need initial investments of $649.27 and $1273.79, respectively.
|
||||
|
||||
"""
|
||||
when = _convert_when(when)
|
||||
(rate, nper, pmt, fv, when) = map(np.asarray, [rate, nper, pmt, fv, when])
|
||||
temp = (1+rate)**nper
|
||||
fact = np.where(rate == 0, nper, (1+rate*when)*(temp-1)/rate)
|
||||
return -(fv + pmt*fact)/temp
|
||||
|
||||
# Computed with Sage
|
||||
# (y + (r + 1)^n*x + p*((r + 1)^n - 1)*(r*w + 1)/r)/(n*(r + 1)^(n - 1)*x -
|
||||
# p*((r + 1)^n - 1)*(r*w + 1)/r^2 + n*p*(r + 1)^(n - 1)*(r*w + 1)/r +
|
||||
# p*((r + 1)^n - 1)*w/r)
|
||||
|
||||
def _g_div_gp(r, n, p, x, y, w):
|
||||
t1 = (r+1)**n
|
||||
t2 = (r+1)**(n-1)
|
||||
return ((y + t1*x + p*(t1 - 1)*(r*w + 1)/r) /
|
||||
(n*t2*x - p*(t1 - 1)*(r*w + 1)/(r**2) + n*p*t2*(r*w + 1)/r +
|
||||
p*(t1 - 1)*w/r))
|
||||
|
||||
|
||||
def _rate_dispatcher(nper, pmt, pv, fv, when=None, guess=None, tol=None,
|
||||
maxiter=None):
|
||||
return (nper, pmt, pv, fv)
|
||||
|
||||
|
||||
# Use Newton's iteration until the change is less than 1e-6
|
||||
# for all values or a maximum of 100 iterations is reached.
|
||||
# Newton's rule is
|
||||
# r_{n+1} = r_{n} - g(r_n)/g'(r_n)
|
||||
# where
|
||||
# g(r) is the formula
|
||||
# g'(r) is the derivative with respect to r.
|
||||
@array_function_dispatch(_rate_dispatcher)
|
||||
def rate(nper, pmt, pv, fv, when='end', guess=None, tol=None, maxiter=100):
|
||||
"""
|
||||
Compute the rate of interest per period.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nper : array_like
|
||||
Number of compounding periods
|
||||
pmt : array_like
|
||||
Payment
|
||||
pv : array_like
|
||||
Present value
|
||||
fv : array_like
|
||||
Future value
|
||||
when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
|
||||
When payments are due ('begin' (1) or 'end' (0))
|
||||
guess : Number, optional
|
||||
Starting guess for solving the rate of interest, default 0.1
|
||||
tol : Number, optional
|
||||
Required tolerance for the solution, default 1e-6
|
||||
maxiter : int, optional
|
||||
Maximum iterations in finding the solution
|
||||
|
||||
Notes
|
||||
-----
|
||||
The rate of interest is computed by iteratively solving the
|
||||
(non-linear) equation::
|
||||
|
||||
fv + pv*(1+rate)**nper + pmt*(1+rate*when)/rate * ((1+rate)**nper - 1) = 0
|
||||
|
||||
for ``rate``.
|
||||
|
||||
References
|
||||
----------
|
||||
Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May). Open Document
|
||||
Format for Office Applications (OpenDocument)v1.2, Part 2: Recalculated
|
||||
Formula (OpenFormula) Format - Annotated Version, Pre-Draft 12.
|
||||
Organization for the Advancement of Structured Information Standards
|
||||
(OASIS). Billerica, MA, USA. [ODT Document]. Available:
|
||||
http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
|
||||
OpenDocument-formula-20090508.odt
|
||||
|
||||
"""
|
||||
when = _convert_when(when)
|
||||
default_type = Decimal if isinstance(pmt, Decimal) else float
|
||||
|
||||
# Handle casting defaults to Decimal if/when pmt is a Decimal and
|
||||
# guess and/or tol are not given default values
|
||||
if guess is None:
|
||||
guess = default_type('0.1')
|
||||
|
||||
if tol is None:
|
||||
tol = default_type('1e-6')
|
||||
|
||||
(nper, pmt, pv, fv, when) = map(np.asarray, [nper, pmt, pv, fv, when])
|
||||
|
||||
rn = guess
|
||||
iterator = 0
|
||||
close = False
|
||||
while (iterator < maxiter) and not close:
|
||||
rnp1 = rn - _g_div_gp(rn, nper, pmt, pv, fv, when)
|
||||
diff = abs(rnp1-rn)
|
||||
close = np.all(diff < tol)
|
||||
iterator += 1
|
||||
rn = rnp1
|
||||
if not close:
|
||||
# Return nan's in array of the same shape as rn
|
||||
return np.nan + rn
|
||||
else:
|
||||
return rn
|
||||
|
||||
|
||||
def _irr_dispatcher(values):
|
||||
return (values,)
|
||||
|
||||
|
||||
@array_function_dispatch(_irr_dispatcher)
|
||||
def irr(values):
|
||||
"""
|
||||
Return the Internal Rate of Return (IRR).
|
||||
|
||||
This is the "average" periodically compounded rate of return
|
||||
that gives a net present value of 0.0; for a more complete explanation,
|
||||
see Notes below.
|
||||
|
||||
:class:`decimal.Decimal` type is not supported.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
values : array_like, shape(N,)
|
||||
Input cash flows per time period. By convention, net "deposits"
|
||||
are negative and net "withdrawals" are positive. Thus, for
|
||||
example, at least the first element of `values`, which represents
|
||||
the initial investment, will typically be negative.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : float
|
||||
Internal Rate of Return for periodic input values.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The IRR is perhaps best understood through an example (illustrated
|
||||
using np.irr in the Examples section below). Suppose one invests 100
|
||||
units and then makes the following withdrawals at regular (fixed)
|
||||
intervals: 39, 59, 55, 20. Assuming the ending value is 0, one's 100
|
||||
unit investment yields 173 units; however, due to the combination of
|
||||
compounding and the periodic withdrawals, the "average" rate of return
|
||||
is neither simply 0.73/4 nor (1.73)^0.25-1. Rather, it is the solution
|
||||
(for :math:`r`) of the equation:
|
||||
|
||||
.. math:: -100 + \\frac{39}{1+r} + \\frac{59}{(1+r)^2}
|
||||
+ \\frac{55}{(1+r)^3} + \\frac{20}{(1+r)^4} = 0
|
||||
|
||||
In general, for `values` :math:`= [v_0, v_1, ... v_M]`,
|
||||
irr is the solution of the equation: [G]_
|
||||
|
||||
.. math:: \\sum_{t=0}^M{\\frac{v_t}{(1+irr)^{t}}} = 0
|
||||
|
||||
References
|
||||
----------
|
||||
.. [G] L. J. Gitman, "Principles of Managerial Finance, Brief," 3rd ed.,
|
||||
Addison-Wesley, 2003, pg. 348.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> round(irr([-100, 39, 59, 55, 20]), 5)
|
||||
0.28095
|
||||
>>> round(irr([-100, 0, 0, 74]), 5)
|
||||
-0.0955
|
||||
>>> round(irr([-100, 100, 0, -7]), 5)
|
||||
-0.0833
|
||||
>>> round(irr([-100, 100, 0, 7]), 5)
|
||||
0.06206
|
||||
>>> round(irr([-5, 10.5, 1, -8, 1]), 5)
|
||||
0.0886
|
||||
|
||||
(Compare with the Example given for numpy.lib.financial.npv)
|
||||
|
||||
"""
|
||||
# `np.roots` call is why this function does not support Decimal type.
|
||||
#
|
||||
# Ultimately Decimal support needs to be added to np.roots, which has
|
||||
# greater implications on the entire linear algebra module and how it does
|
||||
# eigenvalue computations.
|
||||
res = np.roots(values[::-1])
|
||||
mask = (res.imag == 0) & (res.real > 0)
|
||||
if not mask.any():
|
||||
return np.nan
|
||||
res = res[mask].real
|
||||
# NPV(rate) = 0 can have more than one solution so we return
|
||||
# only the solution closest to zero.
|
||||
rate = 1/res - 1
|
||||
rate = rate.item(np.argmin(np.abs(rate)))
|
||||
return rate
|
||||
|
||||
|
||||
def _npv_dispatcher(rate, values):
|
||||
return (values,)
|
||||
|
||||
|
||||
@array_function_dispatch(_npv_dispatcher)
|
||||
def npv(rate, values):
|
||||
"""
|
||||
Returns the NPV (Net Present Value) of a cash flow series.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rate : scalar
|
||||
The discount rate.
|
||||
values : array_like, shape(M, )
|
||||
The values of the time series of cash flows. The (fixed) time
|
||||
interval between cash flow "events" must be the same as that for
|
||||
which `rate` is given (i.e., if `rate` is per year, then precisely
|
||||
a year is understood to elapse between each cash flow event). By
|
||||
convention, investments or "deposits" are negative, income or
|
||||
"withdrawals" are positive; `values` must begin with the initial
|
||||
investment, thus `values[0]` will typically be negative.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : float
|
||||
The NPV of the input cash flow series `values` at the discount
|
||||
`rate`.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Returns the result of: [G]_
|
||||
|
||||
.. math :: \\sum_{t=0}^{M-1}{\\frac{values_t}{(1+rate)^{t}}}
|
||||
|
||||
References
|
||||
----------
|
||||
.. [G] L. J. Gitman, "Principles of Managerial Finance, Brief," 3rd ed.,
|
||||
Addison-Wesley, 2003, pg. 346.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.npv(0.281,[-100, 39, 59, 55, 20])
|
||||
-0.0084785916384548798
|
||||
|
||||
(Compare with the Example given for numpy.lib.financial.irr)
|
||||
|
||||
"""
|
||||
values = np.asarray(values)
|
||||
return (values / (1+rate)**np.arange(0, len(values))).sum(axis=0)
|
||||
|
||||
|
||||
def _mirr_dispatcher(values, finance_rate, reinvest_rate):
|
||||
return (values,)
|
||||
|
||||
|
||||
@array_function_dispatch(_mirr_dispatcher)
|
||||
def mirr(values, finance_rate, reinvest_rate):
|
||||
"""
|
||||
Modified internal rate of return.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
values : array_like
|
||||
Cash flows (must contain at least one positive and one negative
|
||||
value) or nan is returned. The first value is considered a sunk
|
||||
cost at time zero.
|
||||
finance_rate : scalar
|
||||
Interest rate paid on the cash flows
|
||||
reinvest_rate : scalar
|
||||
Interest rate received on the cash flows upon reinvestment
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : float
|
||||
Modified internal rate of return
|
||||
|
||||
"""
|
||||
values = np.asarray(values)
|
||||
n = values.size
|
||||
|
||||
# Without this explicit cast the 1/(n - 1) computation below
|
||||
# becomes a float, which causes TypeError when using Decimal
|
||||
# values.
|
||||
if isinstance(finance_rate, Decimal):
|
||||
n = Decimal(n)
|
||||
|
||||
pos = values > 0
|
||||
neg = values < 0
|
||||
if not (pos.any() and neg.any()):
|
||||
return np.nan
|
||||
numer = np.abs(npv(reinvest_rate, values*pos))
|
||||
denom = np.abs(npv(finance_rate, values*neg))
|
||||
return (numer/denom)**(1/(n - 1))*(1 + reinvest_rate) - 1
|
||||
@@ -0,0 +1,875 @@
|
||||
"""
|
||||
Binary serialization
|
||||
|
||||
NPY format
|
||||
==========
|
||||
|
||||
A simple format for saving numpy arrays to disk with the full
|
||||
information about them.
|
||||
|
||||
The ``.npy`` format is the standard binary file format in NumPy for
|
||||
persisting a *single* arbitrary NumPy array on disk. The format stores all
|
||||
of the shape and dtype information necessary to reconstruct the array
|
||||
correctly even on another machine with a different architecture.
|
||||
The format is designed to be as simple as possible while achieving
|
||||
its limited goals.
|
||||
|
||||
The ``.npz`` format is the standard format for persisting *multiple* NumPy
|
||||
arrays on disk. A ``.npz`` file is a zip file containing multiple ``.npy``
|
||||
files, one for each array.
|
||||
|
||||
Capabilities
|
||||
------------
|
||||
|
||||
- Can represent all NumPy arrays including nested record arrays and
|
||||
object arrays.
|
||||
|
||||
- Represents the data in its native binary form.
|
||||
|
||||
- Supports Fortran-contiguous arrays directly.
|
||||
|
||||
- Stores all of the necessary information to reconstruct the array
|
||||
including shape and dtype on a machine of a different
|
||||
architecture. Both little-endian and big-endian arrays are
|
||||
supported, and a file with little-endian numbers will yield
|
||||
a little-endian array on any machine reading the file. The
|
||||
types are described in terms of their actual sizes. For example,
|
||||
if a machine with a 64-bit C "long int" writes out an array with
|
||||
"long ints", a reading machine with 32-bit C "long ints" will yield
|
||||
an array with 64-bit integers.
|
||||
|
||||
- Is straightforward to reverse engineer. Datasets often live longer than
|
||||
the programs that created them. A competent developer should be
|
||||
able to create a solution in their preferred programming language to
|
||||
read most ``.npy`` files that he has been given without much
|
||||
documentation.
|
||||
|
||||
- Allows memory-mapping of the data. See `open_memmep`.
|
||||
|
||||
- Can be read from a filelike stream object instead of an actual file.
|
||||
|
||||
- Stores object arrays, i.e. arrays containing elements that are arbitrary
|
||||
Python objects. Files with object arrays are not to be mmapable, but
|
||||
can be read and written to disk.
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
- Arbitrary subclasses of numpy.ndarray are not completely preserved.
|
||||
Subclasses will be accepted for writing, but only the array data will
|
||||
be written out. A regular numpy.ndarray object will be created
|
||||
upon reading the file.
|
||||
|
||||
.. warning::
|
||||
|
||||
Due to limitations in the interpretation of structured dtypes, dtypes
|
||||
with fields with empty names will have the names replaced by 'f0', 'f1',
|
||||
etc. Such arrays will not round-trip through the format entirely
|
||||
accurately. The data is intact; only the field names will differ. We are
|
||||
working on a fix for this. This fix will not require a change in the
|
||||
file format. The arrays with such structures can still be saved and
|
||||
restored, and the correct dtype may be restored by using the
|
||||
``loadedarray.view(correct_dtype)`` method.
|
||||
|
||||
File extensions
|
||||
---------------
|
||||
|
||||
We recommend using the ``.npy`` and ``.npz`` extensions for files saved
|
||||
in this format. This is by no means a requirement; applications may wish
|
||||
to use these file formats but use an extension specific to the
|
||||
application. In the absence of an obvious alternative, however,
|
||||
we suggest using ``.npy`` and ``.npz``.
|
||||
|
||||
Version numbering
|
||||
-----------------
|
||||
|
||||
The version numbering of these formats is independent of NumPy version
|
||||
numbering. If the format is upgraded, the code in `numpy.io` will still
|
||||
be able to read and write Version 1.0 files.
|
||||
|
||||
Format Version 1.0
|
||||
------------------
|
||||
|
||||
The first 6 bytes are a magic string: exactly ``\\x93NUMPY``.
|
||||
|
||||
The next 1 byte is an unsigned byte: the major version number of the file
|
||||
format, e.g. ``\\x01``.
|
||||
|
||||
The next 1 byte is an unsigned byte: the minor version number of the file
|
||||
format, e.g. ``\\x00``. Note: the version of the file format is not tied
|
||||
to the version of the numpy package.
|
||||
|
||||
The next 2 bytes form a little-endian unsigned short int: the length of
|
||||
the header data HEADER_LEN.
|
||||
|
||||
The next HEADER_LEN bytes form the header data describing the array's
|
||||
format. It is an ASCII string which contains a Python literal expression
|
||||
of a dictionary. It is terminated by a newline (``\\n``) and padded with
|
||||
spaces (``\\x20``) to make the total of
|
||||
``len(magic string) + 2 + len(length) + HEADER_LEN`` be evenly divisible
|
||||
by 64 for alignment purposes.
|
||||
|
||||
The dictionary contains three keys:
|
||||
|
||||
"descr" : dtype.descr
|
||||
An object that can be passed as an argument to the `numpy.dtype`
|
||||
constructor to create the array's dtype.
|
||||
"fortran_order" : bool
|
||||
Whether the array data is Fortran-contiguous or not. Since
|
||||
Fortran-contiguous arrays are a common form of non-C-contiguity,
|
||||
we allow them to be written directly to disk for efficiency.
|
||||
"shape" : tuple of int
|
||||
The shape of the array.
|
||||
|
||||
For repeatability and readability, the dictionary keys are sorted in
|
||||
alphabetic order. This is for convenience only. A writer SHOULD implement
|
||||
this if possible. A reader MUST NOT depend on this.
|
||||
|
||||
Following the header comes the array data. If the dtype contains Python
|
||||
objects (i.e. ``dtype.hasobject is True``), then the data is a Python
|
||||
pickle of the array. Otherwise the data is the contiguous (either C-
|
||||
or Fortran-, depending on ``fortran_order``) bytes of the array.
|
||||
Consumers can figure out the number of bytes by multiplying the number
|
||||
of elements given by the shape (noting that ``shape=()`` means there is
|
||||
1 element) by ``dtype.itemsize``.
|
||||
|
||||
Format Version 2.0
|
||||
------------------
|
||||
|
||||
The version 1.0 format only allowed the array header to have a total size of
|
||||
65535 bytes. This can be exceeded by structured arrays with a large number of
|
||||
columns. The version 2.0 format extends the header size to 4 GiB.
|
||||
`numpy.save` will automatically save in 2.0 format if the data requires it,
|
||||
else it will always use the more compatible 1.0 format.
|
||||
|
||||
The description of the fourth element of the header therefore has become:
|
||||
"The next 4 bytes form a little-endian unsigned int: the length of the header
|
||||
data HEADER_LEN."
|
||||
|
||||
Notes
|
||||
-----
|
||||
The ``.npy`` format, including motivation for creating it and a comparison of
|
||||
alternatives, is described in the `"npy-format" NEP
|
||||
<https://www.numpy.org/neps/nep-0001-npy-format.html>`_, however details have
|
||||
evolved with time and this document is more current.
|
||||
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import numpy
|
||||
import sys
|
||||
import io
|
||||
import warnings
|
||||
from numpy.lib.utils import safe_eval
|
||||
from numpy.compat import (
|
||||
asbytes, asstr, isfileobj, long, os_fspath
|
||||
)
|
||||
from numpy.core.numeric import pickle
|
||||
|
||||
|
||||
MAGIC_PREFIX = b'\x93NUMPY'
|
||||
MAGIC_LEN = len(MAGIC_PREFIX) + 2
|
||||
ARRAY_ALIGN = 64 # plausible values are powers of 2 between 16 and 4096
|
||||
BUFFER_SIZE = 2**18 # size of buffer for reading npz files in bytes
|
||||
|
||||
# difference between version 1.0 and 2.0 is a 4 byte (I) header length
|
||||
# instead of 2 bytes (H) allowing storage of large structured arrays
|
||||
|
||||
def _check_version(version):
|
||||
if version not in [(1, 0), (2, 0), None]:
|
||||
msg = "we only support format version (1,0) and (2, 0), not %s"
|
||||
raise ValueError(msg % (version,))
|
||||
|
||||
def magic(major, minor):
|
||||
""" Return the magic string for the given file format version.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
major : int in [0, 255]
|
||||
minor : int in [0, 255]
|
||||
|
||||
Returns
|
||||
-------
|
||||
magic : str
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError if the version cannot be formatted.
|
||||
"""
|
||||
if major < 0 or major > 255:
|
||||
raise ValueError("major version must be 0 <= major < 256")
|
||||
if minor < 0 or minor > 255:
|
||||
raise ValueError("minor version must be 0 <= minor < 256")
|
||||
if sys.version_info[0] < 3:
|
||||
return MAGIC_PREFIX + chr(major) + chr(minor)
|
||||
else:
|
||||
return MAGIC_PREFIX + bytes([major, minor])
|
||||
|
||||
def read_magic(fp):
|
||||
""" Read the magic string to get the version of the file format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fp : filelike object
|
||||
|
||||
Returns
|
||||
-------
|
||||
major : int
|
||||
minor : int
|
||||
"""
|
||||
magic_str = _read_bytes(fp, MAGIC_LEN, "magic string")
|
||||
if magic_str[:-2] != MAGIC_PREFIX:
|
||||
msg = "the magic string is not correct; expected %r, got %r"
|
||||
raise ValueError(msg % (MAGIC_PREFIX, magic_str[:-2]))
|
||||
if sys.version_info[0] < 3:
|
||||
major, minor = map(ord, magic_str[-2:])
|
||||
else:
|
||||
major, minor = magic_str[-2:]
|
||||
return major, minor
|
||||
|
||||
def dtype_to_descr(dtype):
|
||||
"""
|
||||
Get a serializable descriptor from the dtype.
|
||||
|
||||
The .descr attribute of a dtype object cannot be round-tripped through
|
||||
the dtype() constructor. Simple types, like dtype('float32'), have
|
||||
a descr which looks like a record array with one field with '' as
|
||||
a name. The dtype() constructor interprets this as a request to give
|
||||
a default name. Instead, we construct descriptor that can be passed to
|
||||
dtype().
|
||||
|
||||
Parameters
|
||||
----------
|
||||
dtype : dtype
|
||||
The dtype of the array that will be written to disk.
|
||||
|
||||
Returns
|
||||
-------
|
||||
descr : object
|
||||
An object that can be passed to `numpy.dtype()` in order to
|
||||
replicate the input dtype.
|
||||
|
||||
"""
|
||||
if dtype.names is not None:
|
||||
# This is a record array. The .descr is fine. XXX: parts of the
|
||||
# record array with an empty name, like padding bytes, still get
|
||||
# fiddled with. This needs to be fixed in the C implementation of
|
||||
# dtype().
|
||||
return dtype.descr
|
||||
else:
|
||||
return dtype.str
|
||||
|
||||
def descr_to_dtype(descr):
|
||||
'''
|
||||
descr may be stored as dtype.descr, which is a list of
|
||||
(name, format, [shape]) tuples. Offsets are not explicitly saved, rather
|
||||
empty fields with name,format == '', '|Vn' are added as padding.
|
||||
|
||||
This function reverses the process, eliminating the empty padding fields.
|
||||
'''
|
||||
if isinstance(descr, (str, dict)):
|
||||
# No padding removal needed
|
||||
return numpy.dtype(descr)
|
||||
|
||||
fields = []
|
||||
offset = 0
|
||||
for field in descr:
|
||||
if len(field) == 2:
|
||||
name, descr_str = field
|
||||
dt = descr_to_dtype(descr_str)
|
||||
else:
|
||||
name, descr_str, shape = field
|
||||
dt = numpy.dtype((descr_to_dtype(descr_str), shape))
|
||||
|
||||
# Ignore padding bytes, which will be void bytes with '' as name
|
||||
# Once support for blank names is removed, only "if name == ''" needed)
|
||||
is_pad = (name == '' and dt.type is numpy.void and dt.names is None)
|
||||
if not is_pad:
|
||||
fields.append((name, dt, offset))
|
||||
|
||||
offset += dt.itemsize
|
||||
|
||||
names, formats, offsets = zip(*fields)
|
||||
# names may be (title, names) tuples
|
||||
nametups = (n if isinstance(n, tuple) else (None, n) for n in names)
|
||||
titles, names = zip(*nametups)
|
||||
return numpy.dtype({'names': names, 'formats': formats, 'titles': titles,
|
||||
'offsets': offsets, 'itemsize': offset})
|
||||
|
||||
def header_data_from_array_1_0(array):
|
||||
""" Get the dictionary of header metadata from a numpy.ndarray.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
array : numpy.ndarray
|
||||
|
||||
Returns
|
||||
-------
|
||||
d : dict
|
||||
This has the appropriate entries for writing its string representation
|
||||
to the header of the file.
|
||||
"""
|
||||
d = {'shape': array.shape}
|
||||
if array.flags.c_contiguous:
|
||||
d['fortran_order'] = False
|
||||
elif array.flags.f_contiguous:
|
||||
d['fortran_order'] = True
|
||||
else:
|
||||
# Totally non-contiguous data. We will have to make it C-contiguous
|
||||
# before writing. Note that we need to test for C_CONTIGUOUS first
|
||||
# because a 1-D array is both C_CONTIGUOUS and F_CONTIGUOUS.
|
||||
d['fortran_order'] = False
|
||||
|
||||
d['descr'] = dtype_to_descr(array.dtype)
|
||||
return d
|
||||
|
||||
def _write_array_header(fp, d, version=None):
|
||||
""" Write the header for an array and returns the version used
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fp : filelike object
|
||||
d : dict
|
||||
This has the appropriate entries for writing its string representation
|
||||
to the header of the file.
|
||||
version: tuple or None
|
||||
None means use oldest that works
|
||||
explicit version will raise a ValueError if the format does not
|
||||
allow saving this data. Default: None
|
||||
Returns
|
||||
-------
|
||||
version : tuple of int
|
||||
the file version which needs to be used to store the data
|
||||
"""
|
||||
import struct
|
||||
header = ["{"]
|
||||
for key, value in sorted(d.items()):
|
||||
# Need to use repr here, since we eval these when reading
|
||||
header.append("'%s': %s, " % (key, repr(value)))
|
||||
header.append("}")
|
||||
header = "".join(header)
|
||||
header = asbytes(_filter_header(header))
|
||||
|
||||
hlen = len(header) + 1 # 1 for newline
|
||||
padlen_v1 = ARRAY_ALIGN - ((MAGIC_LEN + struct.calcsize('<H') + hlen) % ARRAY_ALIGN)
|
||||
padlen_v2 = ARRAY_ALIGN - ((MAGIC_LEN + struct.calcsize('<I') + hlen) % ARRAY_ALIGN)
|
||||
|
||||
# Which version(s) we write depends on the total header size; v1 has a max of 65535
|
||||
if hlen + padlen_v1 < 2**16 and version in (None, (1, 0)):
|
||||
version = (1, 0)
|
||||
header_prefix = magic(1, 0) + struct.pack('<H', hlen + padlen_v1)
|
||||
topad = padlen_v1
|
||||
elif hlen + padlen_v2 < 2**32 and version in (None, (2, 0)):
|
||||
version = (2, 0)
|
||||
header_prefix = magic(2, 0) + struct.pack('<I', hlen + padlen_v2)
|
||||
topad = padlen_v2
|
||||
else:
|
||||
msg = "Header length %s too big for version=%s"
|
||||
msg %= (hlen, version)
|
||||
raise ValueError(msg)
|
||||
|
||||
# Pad the header with spaces and a final newline such that the magic
|
||||
# string, the header-length short and the header are aligned on a
|
||||
# ARRAY_ALIGN byte boundary. This supports memory mapping of dtypes
|
||||
# aligned up to ARRAY_ALIGN on systems like Linux where mmap()
|
||||
# offset must be page-aligned (i.e. the beginning of the file).
|
||||
header = header + b' '*topad + b'\n'
|
||||
|
||||
fp.write(header_prefix)
|
||||
fp.write(header)
|
||||
return version
|
||||
|
||||
def write_array_header_1_0(fp, d):
|
||||
""" Write the header for an array using the 1.0 format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fp : filelike object
|
||||
d : dict
|
||||
This has the appropriate entries for writing its string
|
||||
representation to the header of the file.
|
||||
"""
|
||||
_write_array_header(fp, d, (1, 0))
|
||||
|
||||
|
||||
def write_array_header_2_0(fp, d):
|
||||
""" Write the header for an array using the 2.0 format.
|
||||
The 2.0 format allows storing very large structured arrays.
|
||||
|
||||
.. versionadded:: 1.9.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fp : filelike object
|
||||
d : dict
|
||||
This has the appropriate entries for writing its string
|
||||
representation to the header of the file.
|
||||
"""
|
||||
_write_array_header(fp, d, (2, 0))
|
||||
|
||||
def read_array_header_1_0(fp):
|
||||
"""
|
||||
Read an array header from a filelike object using the 1.0 file format
|
||||
version.
|
||||
|
||||
This will leave the file object located just after the header.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fp : filelike object
|
||||
A file object or something with a `.read()` method like a file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
shape : tuple of int
|
||||
The shape of the array.
|
||||
fortran_order : bool
|
||||
The array data will be written out directly if it is either
|
||||
C-contiguous or Fortran-contiguous. Otherwise, it will be made
|
||||
contiguous before writing it out.
|
||||
dtype : dtype
|
||||
The dtype of the file's data.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If the data is invalid.
|
||||
|
||||
"""
|
||||
return _read_array_header(fp, version=(1, 0))
|
||||
|
||||
def read_array_header_2_0(fp):
|
||||
"""
|
||||
Read an array header from a filelike object using the 2.0 file format
|
||||
version.
|
||||
|
||||
This will leave the file object located just after the header.
|
||||
|
||||
.. versionadded:: 1.9.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fp : filelike object
|
||||
A file object or something with a `.read()` method like a file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
shape : tuple of int
|
||||
The shape of the array.
|
||||
fortran_order : bool
|
||||
The array data will be written out directly if it is either
|
||||
C-contiguous or Fortran-contiguous. Otherwise, it will be made
|
||||
contiguous before writing it out.
|
||||
dtype : dtype
|
||||
The dtype of the file's data.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If the data is invalid.
|
||||
|
||||
"""
|
||||
return _read_array_header(fp, version=(2, 0))
|
||||
|
||||
|
||||
def _filter_header(s):
|
||||
"""Clean up 'L' in npz header ints.
|
||||
|
||||
Cleans up the 'L' in strings representing integers. Needed to allow npz
|
||||
headers produced in Python2 to be read in Python3.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
s : byte string
|
||||
Npy file header.
|
||||
|
||||
Returns
|
||||
-------
|
||||
header : str
|
||||
Cleaned up header.
|
||||
|
||||
"""
|
||||
import tokenize
|
||||
if sys.version_info[0] >= 3:
|
||||
from io import StringIO
|
||||
else:
|
||||
from StringIO import StringIO
|
||||
|
||||
tokens = []
|
||||
last_token_was_number = False
|
||||
# adding newline as python 2.7.5 workaround
|
||||
string = asstr(s) + "\n"
|
||||
for token in tokenize.generate_tokens(StringIO(string).readline):
|
||||
token_type = token[0]
|
||||
token_string = token[1]
|
||||
if (last_token_was_number and
|
||||
token_type == tokenize.NAME and
|
||||
token_string == "L"):
|
||||
continue
|
||||
else:
|
||||
tokens.append(token)
|
||||
last_token_was_number = (token_type == tokenize.NUMBER)
|
||||
# removing newline (see above) as python 2.7.5 workaround
|
||||
return tokenize.untokenize(tokens)[:-1]
|
||||
|
||||
|
||||
def _read_array_header(fp, version):
|
||||
"""
|
||||
see read_array_header_1_0
|
||||
"""
|
||||
# Read an unsigned, little-endian short int which has the length of the
|
||||
# header.
|
||||
import struct
|
||||
if version == (1, 0):
|
||||
hlength_type = '<H'
|
||||
elif version == (2, 0):
|
||||
hlength_type = '<I'
|
||||
else:
|
||||
raise ValueError("Invalid version %r" % version)
|
||||
|
||||
hlength_str = _read_bytes(fp, struct.calcsize(hlength_type), "array header length")
|
||||
header_length = struct.unpack(hlength_type, hlength_str)[0]
|
||||
header = _read_bytes(fp, header_length, "array header")
|
||||
|
||||
# The header is a pretty-printed string representation of a literal
|
||||
# Python dictionary with trailing newlines padded to a ARRAY_ALIGN byte
|
||||
# boundary. The keys are strings.
|
||||
# "shape" : tuple of int
|
||||
# "fortran_order" : bool
|
||||
# "descr" : dtype.descr
|
||||
header = _filter_header(header)
|
||||
try:
|
||||
d = safe_eval(header)
|
||||
except SyntaxError as e:
|
||||
msg = "Cannot parse header: %r\nException: %r"
|
||||
raise ValueError(msg % (header, e))
|
||||
if not isinstance(d, dict):
|
||||
msg = "Header is not a dictionary: %r"
|
||||
raise ValueError(msg % d)
|
||||
keys = sorted(d.keys())
|
||||
if keys != ['descr', 'fortran_order', 'shape']:
|
||||
msg = "Header does not contain the correct keys: %r"
|
||||
raise ValueError(msg % (keys,))
|
||||
|
||||
# Sanity-check the values.
|
||||
if (not isinstance(d['shape'], tuple) or
|
||||
not numpy.all([isinstance(x, (int, long)) for x in d['shape']])):
|
||||
msg = "shape is not valid: %r"
|
||||
raise ValueError(msg % (d['shape'],))
|
||||
if not isinstance(d['fortran_order'], bool):
|
||||
msg = "fortran_order is not a valid bool: %r"
|
||||
raise ValueError(msg % (d['fortran_order'],))
|
||||
try:
|
||||
dtype = descr_to_dtype(d['descr'])
|
||||
except TypeError as e:
|
||||
msg = "descr is not a valid dtype descriptor: %r"
|
||||
raise ValueError(msg % (d['descr'],))
|
||||
|
||||
return d['shape'], d['fortran_order'], dtype
|
||||
|
||||
def write_array(fp, array, version=None, allow_pickle=True, pickle_kwargs=None):
|
||||
"""
|
||||
Write an array to an NPY file, including a header.
|
||||
|
||||
If the array is neither C-contiguous nor Fortran-contiguous AND the
|
||||
file_like object is not a real file object, this function will have to
|
||||
copy data in memory.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fp : file_like object
|
||||
An open, writable file object, or similar object with a
|
||||
``.write()`` method.
|
||||
array : ndarray
|
||||
The array to write to disk.
|
||||
version : (int, int) or None, optional
|
||||
The version number of the format. None means use the oldest
|
||||
supported version that is able to store the data. Default: None
|
||||
allow_pickle : bool, optional
|
||||
Whether to allow writing pickled data. Default: True
|
||||
pickle_kwargs : dict, optional
|
||||
Additional keyword arguments to pass to pickle.dump, excluding
|
||||
'protocol'. These are only useful when pickling objects in object
|
||||
arrays on Python 3 to Python 2 compatible format.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If the array cannot be persisted. This includes the case of
|
||||
allow_pickle=False and array being an object array.
|
||||
Various other errors
|
||||
If the array contains Python objects as part of its dtype, the
|
||||
process of pickling them may raise various errors if the objects
|
||||
are not picklable.
|
||||
|
||||
"""
|
||||
_check_version(version)
|
||||
used_ver = _write_array_header(fp, header_data_from_array_1_0(array),
|
||||
version)
|
||||
# this warning can be removed when 1.9 has aged enough
|
||||
if version != (2, 0) and used_ver == (2, 0):
|
||||
warnings.warn("Stored array in format 2.0. It can only be"
|
||||
"read by NumPy >= 1.9", UserWarning, stacklevel=2)
|
||||
|
||||
if array.itemsize == 0:
|
||||
buffersize = 0
|
||||
else:
|
||||
# Set buffer size to 16 MiB to hide the Python loop overhead.
|
||||
buffersize = max(16 * 1024 ** 2 // array.itemsize, 1)
|
||||
|
||||
if array.dtype.hasobject:
|
||||
# We contain Python objects so we cannot write out the data
|
||||
# directly. Instead, we will pickle it out with version 2 of the
|
||||
# pickle protocol.
|
||||
if not allow_pickle:
|
||||
raise ValueError("Object arrays cannot be saved when "
|
||||
"allow_pickle=False")
|
||||
if pickle_kwargs is None:
|
||||
pickle_kwargs = {}
|
||||
pickle.dump(array, fp, protocol=2, **pickle_kwargs)
|
||||
elif array.flags.f_contiguous and not array.flags.c_contiguous:
|
||||
if isfileobj(fp):
|
||||
array.T.tofile(fp)
|
||||
else:
|
||||
for chunk in numpy.nditer(
|
||||
array, flags=['external_loop', 'buffered', 'zerosize_ok'],
|
||||
buffersize=buffersize, order='F'):
|
||||
fp.write(chunk.tobytes('C'))
|
||||
else:
|
||||
if isfileobj(fp):
|
||||
array.tofile(fp)
|
||||
else:
|
||||
for chunk in numpy.nditer(
|
||||
array, flags=['external_loop', 'buffered', 'zerosize_ok'],
|
||||
buffersize=buffersize, order='C'):
|
||||
fp.write(chunk.tobytes('C'))
|
||||
|
||||
|
||||
def read_array(fp, allow_pickle=True, pickle_kwargs=None):
|
||||
"""
|
||||
Read an array from an NPY file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fp : file_like object
|
||||
If this is not a real file object, then this may take extra memory
|
||||
and time.
|
||||
allow_pickle : bool, optional
|
||||
Whether to allow reading pickled data. Default: True
|
||||
pickle_kwargs : dict
|
||||
Additional keyword arguments to pass to pickle.load. These are only
|
||||
useful when loading object arrays saved on Python 2 when using
|
||||
Python 3.
|
||||
|
||||
Returns
|
||||
-------
|
||||
array : ndarray
|
||||
The array from the data on disk.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If the data is invalid, or allow_pickle=False and the file contains
|
||||
an object array.
|
||||
|
||||
"""
|
||||
version = read_magic(fp)
|
||||
_check_version(version)
|
||||
shape, fortran_order, dtype = _read_array_header(fp, version)
|
||||
if len(shape) == 0:
|
||||
count = 1
|
||||
else:
|
||||
count = numpy.multiply.reduce(shape, dtype=numpy.int64)
|
||||
|
||||
# Now read the actual data.
|
||||
if dtype.hasobject:
|
||||
# The array contained Python objects. We need to unpickle the data.
|
||||
if not allow_pickle:
|
||||
raise ValueError("Object arrays cannot be loaded when "
|
||||
"allow_pickle=False")
|
||||
if pickle_kwargs is None:
|
||||
pickle_kwargs = {}
|
||||
try:
|
||||
array = pickle.load(fp, **pickle_kwargs)
|
||||
except UnicodeError as err:
|
||||
if sys.version_info[0] >= 3:
|
||||
# Friendlier error message
|
||||
raise UnicodeError("Unpickling a python object failed: %r\n"
|
||||
"You may need to pass the encoding= option "
|
||||
"to numpy.load" % (err,))
|
||||
raise
|
||||
else:
|
||||
if isfileobj(fp):
|
||||
# We can use the fast fromfile() function.
|
||||
array = numpy.fromfile(fp, dtype=dtype, count=count)
|
||||
else:
|
||||
# This is not a real file. We have to read it the
|
||||
# memory-intensive way.
|
||||
# crc32 module fails on reads greater than 2 ** 32 bytes,
|
||||
# breaking large reads from gzip streams. Chunk reads to
|
||||
# BUFFER_SIZE bytes to avoid issue and reduce memory overhead
|
||||
# of the read. In non-chunked case count < max_read_count, so
|
||||
# only one read is performed.
|
||||
|
||||
# Use np.ndarray instead of np.empty since the latter does
|
||||
# not correctly instantiate zero-width string dtypes; see
|
||||
# https://github.com/numpy/numpy/pull/6430
|
||||
array = numpy.ndarray(count, dtype=dtype)
|
||||
|
||||
if dtype.itemsize > 0:
|
||||
# If dtype.itemsize == 0 then there's nothing more to read
|
||||
max_read_count = BUFFER_SIZE // min(BUFFER_SIZE, dtype.itemsize)
|
||||
|
||||
for i in range(0, count, max_read_count):
|
||||
read_count = min(max_read_count, count - i)
|
||||
read_size = int(read_count * dtype.itemsize)
|
||||
data = _read_bytes(fp, read_size, "array data")
|
||||
array[i:i+read_count] = numpy.frombuffer(data, dtype=dtype,
|
||||
count=read_count)
|
||||
|
||||
if fortran_order:
|
||||
array.shape = shape[::-1]
|
||||
array = array.transpose()
|
||||
else:
|
||||
array.shape = shape
|
||||
|
||||
return array
|
||||
|
||||
|
||||
def open_memmap(filename, mode='r+', dtype=None, shape=None,
|
||||
fortran_order=False, version=None):
|
||||
"""
|
||||
Open a .npy file as a memory-mapped array.
|
||||
|
||||
This may be used to read an existing file or create a new one.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str or path-like
|
||||
The name of the file on disk. This may *not* be a file-like
|
||||
object.
|
||||
mode : str, optional
|
||||
The mode in which to open the file; the default is 'r+'. In
|
||||
addition to the standard file modes, 'c' is also accepted to mean
|
||||
"copy on write." See `memmap` for the available mode strings.
|
||||
dtype : data-type, optional
|
||||
The data type of the array if we are creating a new file in "write"
|
||||
mode, if not, `dtype` is ignored. The default value is None, which
|
||||
results in a data-type of `float64`.
|
||||
shape : tuple of int
|
||||
The shape of the array if we are creating a new file in "write"
|
||||
mode, in which case this parameter is required. Otherwise, this
|
||||
parameter is ignored and is thus optional.
|
||||
fortran_order : bool, optional
|
||||
Whether the array should be Fortran-contiguous (True) or
|
||||
C-contiguous (False, the default) if we are creating a new file in
|
||||
"write" mode.
|
||||
version : tuple of int (major, minor) or None
|
||||
If the mode is a "write" mode, then this is the version of the file
|
||||
format used to create the file. None means use the oldest
|
||||
supported version that is able to store the data. Default: None
|
||||
|
||||
Returns
|
||||
-------
|
||||
marray : memmap
|
||||
The memory-mapped array.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If the data or the mode is invalid.
|
||||
IOError
|
||||
If the file is not found or cannot be opened correctly.
|
||||
|
||||
See Also
|
||||
--------
|
||||
memmap
|
||||
|
||||
"""
|
||||
if isfileobj(filename):
|
||||
raise ValueError("Filename must be a string or a path-like object."
|
||||
" Memmap cannot use existing file handles.")
|
||||
|
||||
if 'w' in mode:
|
||||
# We are creating the file, not reading it.
|
||||
# Check if we ought to create the file.
|
||||
_check_version(version)
|
||||
# Ensure that the given dtype is an authentic dtype object rather
|
||||
# than just something that can be interpreted as a dtype object.
|
||||
dtype = numpy.dtype(dtype)
|
||||
if dtype.hasobject:
|
||||
msg = "Array can't be memory-mapped: Python objects in dtype."
|
||||
raise ValueError(msg)
|
||||
d = dict(
|
||||
descr=dtype_to_descr(dtype),
|
||||
fortran_order=fortran_order,
|
||||
shape=shape,
|
||||
)
|
||||
# If we got here, then it should be safe to create the file.
|
||||
fp = open(os_fspath(filename), mode+'b')
|
||||
try:
|
||||
used_ver = _write_array_header(fp, d, version)
|
||||
# this warning can be removed when 1.9 has aged enough
|
||||
if version != (2, 0) and used_ver == (2, 0):
|
||||
warnings.warn("Stored array in format 2.0. It can only be"
|
||||
"read by NumPy >= 1.9", UserWarning, stacklevel=2)
|
||||
offset = fp.tell()
|
||||
finally:
|
||||
fp.close()
|
||||
else:
|
||||
# Read the header of the file first.
|
||||
fp = open(os_fspath(filename), 'rb')
|
||||
try:
|
||||
version = read_magic(fp)
|
||||
_check_version(version)
|
||||
|
||||
shape, fortran_order, dtype = _read_array_header(fp, version)
|
||||
if dtype.hasobject:
|
||||
msg = "Array can't be memory-mapped: Python objects in dtype."
|
||||
raise ValueError(msg)
|
||||
offset = fp.tell()
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
if fortran_order:
|
||||
order = 'F'
|
||||
else:
|
||||
order = 'C'
|
||||
|
||||
# We need to change a write-only mode to a read-write mode since we've
|
||||
# already written data to the file.
|
||||
if mode == 'w+':
|
||||
mode = 'r+'
|
||||
|
||||
marray = numpy.memmap(filename, dtype=dtype, shape=shape, order=order,
|
||||
mode=mode, offset=offset)
|
||||
|
||||
return marray
|
||||
|
||||
|
||||
def _read_bytes(fp, size, error_template="ran out of data"):
|
||||
"""
|
||||
Read from file-like object until size bytes are read.
|
||||
Raises ValueError if not EOF is encountered before size bytes are read.
|
||||
Non-blocking objects only supported if they derive from io objects.
|
||||
|
||||
Required as e.g. ZipExtFile in python 2.6 can return less data than
|
||||
requested.
|
||||
"""
|
||||
data = bytes()
|
||||
while True:
|
||||
# io files (default in python3) return None or raise on
|
||||
# would-block, python2 file will truncate, probably nothing can be
|
||||
# done about that. note that regular files can't be non-blocking
|
||||
try:
|
||||
r = fp.read(size - len(data))
|
||||
data += r
|
||||
if len(r) == 0 or len(data) == size:
|
||||
break
|
||||
except io.BlockingIOError:
|
||||
pass
|
||||
if len(data) != size:
|
||||
msg = "EOF: reading %s, expected %d bytes got %d"
|
||||
raise ValueError(msg % (error_template, size, len(data)))
|
||||
else:
|
||||
return data
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,965 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import functools
|
||||
import sys
|
||||
import math
|
||||
|
||||
import numpy.core.numeric as _nx
|
||||
from numpy.core.numeric import (
|
||||
asarray, ScalarType, array, alltrue, cumprod, arange, ndim
|
||||
)
|
||||
from numpy.core.numerictypes import find_common_type, issubdtype
|
||||
|
||||
import numpy.matrixlib as matrixlib
|
||||
from .function_base import diff
|
||||
from numpy.core.multiarray import ravel_multi_index, unravel_index
|
||||
from numpy.core.overrides import set_module
|
||||
from numpy.core import overrides, linspace
|
||||
from numpy.lib.stride_tricks import as_strided
|
||||
|
||||
|
||||
array_function_dispatch = functools.partial(
|
||||
overrides.array_function_dispatch, module='numpy')
|
||||
|
||||
|
||||
__all__ = [
|
||||
'ravel_multi_index', 'unravel_index', 'mgrid', 'ogrid', 'r_', 'c_',
|
||||
's_', 'index_exp', 'ix_', 'ndenumerate', 'ndindex', 'fill_diagonal',
|
||||
'diag_indices', 'diag_indices_from'
|
||||
]
|
||||
|
||||
|
||||
def _ix__dispatcher(*args):
|
||||
return args
|
||||
|
||||
|
||||
@array_function_dispatch(_ix__dispatcher)
|
||||
def ix_(*args):
|
||||
"""
|
||||
Construct an open mesh from multiple sequences.
|
||||
|
||||
This function takes N 1-D sequences and returns N outputs with N
|
||||
dimensions each, such that the shape is 1 in all but one dimension
|
||||
and the dimension with the non-unit shape value cycles through all
|
||||
N dimensions.
|
||||
|
||||
Using `ix_` one can quickly construct index arrays that will index
|
||||
the cross product. ``a[np.ix_([1,3],[2,5])]`` returns the array
|
||||
``[[a[1,2] a[1,5]], [a[3,2] a[3,5]]]``.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
args : 1-D sequences
|
||||
Each sequence should be of integer or boolean type.
|
||||
Boolean sequences will be interpreted as boolean masks for the
|
||||
corresponding dimension (equivalent to passing in
|
||||
``np.nonzero(boolean_sequence)``).
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : tuple of ndarrays
|
||||
N arrays with N dimensions each, with N the number of input
|
||||
sequences. Together these arrays form an open mesh.
|
||||
|
||||
See Also
|
||||
--------
|
||||
ogrid, mgrid, meshgrid
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> a = np.arange(10).reshape(2, 5)
|
||||
>>> a
|
||||
array([[0, 1, 2, 3, 4],
|
||||
[5, 6, 7, 8, 9]])
|
||||
>>> ixgrid = np.ix_([0, 1], [2, 4])
|
||||
>>> ixgrid
|
||||
(array([[0],
|
||||
[1]]), array([[2, 4]]))
|
||||
>>> ixgrid[0].shape, ixgrid[1].shape
|
||||
((2, 1), (1, 2))
|
||||
>>> a[ixgrid]
|
||||
array([[2, 4],
|
||||
[7, 9]])
|
||||
|
||||
>>> ixgrid = np.ix_([True, True], [2, 4])
|
||||
>>> a[ixgrid]
|
||||
array([[2, 4],
|
||||
[7, 9]])
|
||||
>>> ixgrid = np.ix_([True, True], [False, False, True, False, True])
|
||||
>>> a[ixgrid]
|
||||
array([[2, 4],
|
||||
[7, 9]])
|
||||
|
||||
"""
|
||||
out = []
|
||||
nd = len(args)
|
||||
for k, new in enumerate(args):
|
||||
new = asarray(new)
|
||||
if new.ndim != 1:
|
||||
raise ValueError("Cross index must be 1 dimensional")
|
||||
if new.size == 0:
|
||||
# Explicitly type empty arrays to avoid float default
|
||||
new = new.astype(_nx.intp)
|
||||
if issubdtype(new.dtype, _nx.bool_):
|
||||
new, = new.nonzero()
|
||||
new = new.reshape((1,)*k + (new.size,) + (1,)*(nd-k-1))
|
||||
out.append(new)
|
||||
return tuple(out)
|
||||
|
||||
class nd_grid(object):
|
||||
"""
|
||||
Construct a multi-dimensional "meshgrid".
|
||||
|
||||
``grid = nd_grid()`` creates an instance which will return a mesh-grid
|
||||
when indexed. The dimension and number of the output arrays are equal
|
||||
to the number of indexing dimensions. If the step length is not a
|
||||
complex number, then the stop is not inclusive.
|
||||
|
||||
However, if the step length is a **complex number** (e.g. 5j), then the
|
||||
integer part of its magnitude is interpreted as specifying the
|
||||
number of points to create between the start and stop values, where
|
||||
the stop value **is inclusive**.
|
||||
|
||||
If instantiated with an argument of ``sparse=True``, the mesh-grid is
|
||||
open (or not fleshed out) so that only one-dimension of each returned
|
||||
argument is greater than 1.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
sparse : bool, optional
|
||||
Whether the grid is sparse or not. Default is False.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Two instances of `nd_grid` are made available in the NumPy namespace,
|
||||
`mgrid` and `ogrid`, approximately defined as::
|
||||
|
||||
mgrid = nd_grid(sparse=False)
|
||||
ogrid = nd_grid(sparse=True)
|
||||
|
||||
Users should use these pre-defined instances instead of using `nd_grid`
|
||||
directly.
|
||||
"""
|
||||
|
||||
def __init__(self, sparse=False):
|
||||
self.sparse = sparse
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
size = []
|
||||
typ = int
|
||||
for k in range(len(key)):
|
||||
step = key[k].step
|
||||
start = key[k].start
|
||||
if start is None:
|
||||
start = 0
|
||||
if step is None:
|
||||
step = 1
|
||||
if isinstance(step, complex):
|
||||
size.append(int(abs(step)))
|
||||
typ = float
|
||||
else:
|
||||
size.append(
|
||||
int(math.ceil((key[k].stop - start)/(step*1.0))))
|
||||
if (isinstance(step, float) or
|
||||
isinstance(start, float) or
|
||||
isinstance(key[k].stop, float)):
|
||||
typ = float
|
||||
if self.sparse:
|
||||
nn = [_nx.arange(_x, dtype=_t)
|
||||
for _x, _t in zip(size, (typ,)*len(size))]
|
||||
else:
|
||||
nn = _nx.indices(size, typ)
|
||||
for k in range(len(size)):
|
||||
step = key[k].step
|
||||
start = key[k].start
|
||||
if start is None:
|
||||
start = 0
|
||||
if step is None:
|
||||
step = 1
|
||||
if isinstance(step, complex):
|
||||
step = int(abs(step))
|
||||
if step != 1:
|
||||
step = (key[k].stop - start)/float(step-1)
|
||||
nn[k] = (nn[k]*step+start)
|
||||
if self.sparse:
|
||||
slobj = [_nx.newaxis]*len(size)
|
||||
for k in range(len(size)):
|
||||
slobj[k] = slice(None, None)
|
||||
nn[k] = nn[k][tuple(slobj)]
|
||||
slobj[k] = _nx.newaxis
|
||||
return nn
|
||||
except (IndexError, TypeError):
|
||||
step = key.step
|
||||
stop = key.stop
|
||||
start = key.start
|
||||
if start is None:
|
||||
start = 0
|
||||
if isinstance(step, complex):
|
||||
step = abs(step)
|
||||
length = int(step)
|
||||
if step != 1:
|
||||
step = (key.stop-start)/float(step-1)
|
||||
stop = key.stop + step
|
||||
return _nx.arange(0, length, 1, float)*step + start
|
||||
else:
|
||||
return _nx.arange(start, stop, step)
|
||||
|
||||
|
||||
class MGridClass(nd_grid):
|
||||
"""
|
||||
`nd_grid` instance which returns a dense multi-dimensional "meshgrid".
|
||||
|
||||
An instance of `numpy.lib.index_tricks.nd_grid` which returns an dense
|
||||
(or fleshed out) mesh-grid when indexed, so that each returned argument
|
||||
has the same shape. The dimensions and number of the output arrays are
|
||||
equal to the number of indexing dimensions. If the step length is not a
|
||||
complex number, then the stop is not inclusive.
|
||||
|
||||
However, if the step length is a **complex number** (e.g. 5j), then
|
||||
the integer part of its magnitude is interpreted as specifying the
|
||||
number of points to create between the start and stop values, where
|
||||
the stop value **is inclusive**.
|
||||
|
||||
Returns
|
||||
----------
|
||||
mesh-grid `ndarrays` all of the same dimensions
|
||||
|
||||
See Also
|
||||
--------
|
||||
numpy.lib.index_tricks.nd_grid : class of `ogrid` and `mgrid` objects
|
||||
ogrid : like mgrid but returns open (not fleshed out) mesh grids
|
||||
r_ : array concatenator
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.mgrid[0:5,0:5]
|
||||
array([[[0, 0, 0, 0, 0],
|
||||
[1, 1, 1, 1, 1],
|
||||
[2, 2, 2, 2, 2],
|
||||
[3, 3, 3, 3, 3],
|
||||
[4, 4, 4, 4, 4]],
|
||||
[[0, 1, 2, 3, 4],
|
||||
[0, 1, 2, 3, 4],
|
||||
[0, 1, 2, 3, 4],
|
||||
[0, 1, 2, 3, 4],
|
||||
[0, 1, 2, 3, 4]]])
|
||||
>>> np.mgrid[-1:1:5j]
|
||||
array([-1. , -0.5, 0. , 0.5, 1. ])
|
||||
|
||||
"""
|
||||
def __init__(self):
|
||||
super(MGridClass, self).__init__(sparse=False)
|
||||
|
||||
mgrid = MGridClass()
|
||||
|
||||
class OGridClass(nd_grid):
|
||||
"""
|
||||
`nd_grid` instance which returns an open multi-dimensional "meshgrid".
|
||||
|
||||
An instance of `numpy.lib.index_tricks.nd_grid` which returns an open
|
||||
(i.e. not fleshed out) mesh-grid when indexed, so that only one dimension
|
||||
of each returned array is greater than 1. The dimension and number of the
|
||||
output arrays are equal to the number of indexing dimensions. If the step
|
||||
length is not a complex number, then the stop is not inclusive.
|
||||
|
||||
However, if the step length is a **complex number** (e.g. 5j), then
|
||||
the integer part of its magnitude is interpreted as specifying the
|
||||
number of points to create between the start and stop values, where
|
||||
the stop value **is inclusive**.
|
||||
|
||||
Returns
|
||||
----------
|
||||
mesh-grid `ndarrays` with only one dimension :math:`\\neq 1`
|
||||
|
||||
See Also
|
||||
--------
|
||||
np.lib.index_tricks.nd_grid : class of `ogrid` and `mgrid` objects
|
||||
mgrid : like `ogrid` but returns dense (or fleshed out) mesh grids
|
||||
r_ : array concatenator
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from numpy import ogrid
|
||||
>>> ogrid[-1:1:5j]
|
||||
array([-1. , -0.5, 0. , 0.5, 1. ])
|
||||
>>> ogrid[0:5,0:5]
|
||||
[array([[0],
|
||||
[1],
|
||||
[2],
|
||||
[3],
|
||||
[4]]), array([[0, 1, 2, 3, 4]])]
|
||||
|
||||
"""
|
||||
def __init__(self):
|
||||
super(OGridClass, self).__init__(sparse=True)
|
||||
|
||||
ogrid = OGridClass()
|
||||
|
||||
|
||||
class AxisConcatenator(object):
|
||||
"""
|
||||
Translates slice objects to concatenation along an axis.
|
||||
|
||||
For detailed documentation on usage, see `r_`.
|
||||
"""
|
||||
# allow ma.mr_ to override this
|
||||
concatenate = staticmethod(_nx.concatenate)
|
||||
makemat = staticmethod(matrixlib.matrix)
|
||||
|
||||
def __init__(self, axis=0, matrix=False, ndmin=1, trans1d=-1):
|
||||
self.axis = axis
|
||||
self.matrix = matrix
|
||||
self.trans1d = trans1d
|
||||
self.ndmin = ndmin
|
||||
|
||||
def __getitem__(self, key):
|
||||
# handle matrix builder syntax
|
||||
if isinstance(key, str):
|
||||
frame = sys._getframe().f_back
|
||||
mymat = matrixlib.bmat(key, frame.f_globals, frame.f_locals)
|
||||
return mymat
|
||||
|
||||
if not isinstance(key, tuple):
|
||||
key = (key,)
|
||||
|
||||
# copy attributes, since they can be overridden in the first argument
|
||||
trans1d = self.trans1d
|
||||
ndmin = self.ndmin
|
||||
matrix = self.matrix
|
||||
axis = self.axis
|
||||
|
||||
objs = []
|
||||
scalars = []
|
||||
arraytypes = []
|
||||
scalartypes = []
|
||||
|
||||
for k, item in enumerate(key):
|
||||
scalar = False
|
||||
if isinstance(item, slice):
|
||||
step = item.step
|
||||
start = item.start
|
||||
stop = item.stop
|
||||
if start is None:
|
||||
start = 0
|
||||
if step is None:
|
||||
step = 1
|
||||
if isinstance(step, complex):
|
||||
size = int(abs(step))
|
||||
newobj = linspace(start, stop, num=size)
|
||||
else:
|
||||
newobj = _nx.arange(start, stop, step)
|
||||
if ndmin > 1:
|
||||
newobj = array(newobj, copy=False, ndmin=ndmin)
|
||||
if trans1d != -1:
|
||||
newobj = newobj.swapaxes(-1, trans1d)
|
||||
elif isinstance(item, str):
|
||||
if k != 0:
|
||||
raise ValueError("special directives must be the "
|
||||
"first entry.")
|
||||
if item in ('r', 'c'):
|
||||
matrix = True
|
||||
col = (item == 'c')
|
||||
continue
|
||||
if ',' in item:
|
||||
vec = item.split(',')
|
||||
try:
|
||||
axis, ndmin = [int(x) for x in vec[:2]]
|
||||
if len(vec) == 3:
|
||||
trans1d = int(vec[2])
|
||||
continue
|
||||
except Exception:
|
||||
raise ValueError("unknown special directive")
|
||||
try:
|
||||
axis = int(item)
|
||||
continue
|
||||
except (ValueError, TypeError):
|
||||
raise ValueError("unknown special directive")
|
||||
elif type(item) in ScalarType:
|
||||
newobj = array(item, ndmin=ndmin)
|
||||
scalars.append(len(objs))
|
||||
scalar = True
|
||||
scalartypes.append(newobj.dtype)
|
||||
else:
|
||||
item_ndim = ndim(item)
|
||||
newobj = array(item, copy=False, subok=True, ndmin=ndmin)
|
||||
if trans1d != -1 and item_ndim < ndmin:
|
||||
k2 = ndmin - item_ndim
|
||||
k1 = trans1d
|
||||
if k1 < 0:
|
||||
k1 += k2 + 1
|
||||
defaxes = list(range(ndmin))
|
||||
axes = defaxes[:k1] + defaxes[k2:] + defaxes[k1:k2]
|
||||
newobj = newobj.transpose(axes)
|
||||
objs.append(newobj)
|
||||
if not scalar and isinstance(newobj, _nx.ndarray):
|
||||
arraytypes.append(newobj.dtype)
|
||||
|
||||
# Ensure that scalars won't up-cast unless warranted
|
||||
final_dtype = find_common_type(arraytypes, scalartypes)
|
||||
if final_dtype is not None:
|
||||
for k in scalars:
|
||||
objs[k] = objs[k].astype(final_dtype)
|
||||
|
||||
res = self.concatenate(tuple(objs), axis=axis)
|
||||
|
||||
if matrix:
|
||||
oldndim = res.ndim
|
||||
res = self.makemat(res)
|
||||
if oldndim == 1 and col:
|
||||
res = res.T
|
||||
return res
|
||||
|
||||
def __len__(self):
|
||||
return 0
|
||||
|
||||
# separate classes are used here instead of just making r_ = concatentor(0),
|
||||
# etc. because otherwise we couldn't get the doc string to come out right
|
||||
# in help(r_)
|
||||
|
||||
class RClass(AxisConcatenator):
|
||||
"""
|
||||
Translates slice objects to concatenation along the first axis.
|
||||
|
||||
This is a simple way to build up arrays quickly. There are two use cases.
|
||||
|
||||
1. If the index expression contains comma separated arrays, then stack
|
||||
them along their first axis.
|
||||
2. If the index expression contains slice notation or scalars then create
|
||||
a 1-D array with a range indicated by the slice notation.
|
||||
|
||||
If slice notation is used, the syntax ``start:stop:step`` is equivalent
|
||||
to ``np.arange(start, stop, step)`` inside of the brackets. However, if
|
||||
``step`` is an imaginary number (i.e. 100j) then its integer portion is
|
||||
interpreted as a number-of-points desired and the start and stop are
|
||||
inclusive. In other words ``start:stop:stepj`` is interpreted as
|
||||
``np.linspace(start, stop, step, endpoint=1)`` inside of the brackets.
|
||||
After expansion of slice notation, all comma separated sequences are
|
||||
concatenated together.
|
||||
|
||||
Optional character strings placed as the first element of the index
|
||||
expression can be used to change the output. The strings 'r' or 'c' result
|
||||
in matrix output. If the result is 1-D and 'r' is specified a 1 x N (row)
|
||||
matrix is produced. If the result is 1-D and 'c' is specified, then a N x 1
|
||||
(column) matrix is produced. If the result is 2-D then both provide the
|
||||
same matrix result.
|
||||
|
||||
A string integer specifies which axis to stack multiple comma separated
|
||||
arrays along. A string of two comma-separated integers allows indication
|
||||
of the minimum number of dimensions to force each entry into as the
|
||||
second integer (the axis to concatenate along is still the first integer).
|
||||
|
||||
A string with three comma-separated integers allows specification of the
|
||||
axis to concatenate along, the minimum number of dimensions to force the
|
||||
entries to, and which axis should contain the start of the arrays which
|
||||
are less than the specified number of dimensions. In other words the third
|
||||
integer allows you to specify where the 1's should be placed in the shape
|
||||
of the arrays that have their shapes upgraded. By default, they are placed
|
||||
in the front of the shape tuple. The third argument allows you to specify
|
||||
where the start of the array should be instead. Thus, a third argument of
|
||||
'0' would place the 1's at the end of the array shape. Negative integers
|
||||
specify where in the new shape tuple the last dimension of upgraded arrays
|
||||
should be placed, so the default is '-1'.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
Not a function, so takes no parameters
|
||||
|
||||
|
||||
Returns
|
||||
-------
|
||||
A concatenated ndarray or matrix.
|
||||
|
||||
See Also
|
||||
--------
|
||||
concatenate : Join a sequence of arrays along an existing axis.
|
||||
c_ : Translates slice objects to concatenation along the second axis.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.r_[np.array([1,2,3]), 0, 0, np.array([4,5,6])]
|
||||
array([1, 2, 3, 0, 0, 4, 5, 6])
|
||||
>>> np.r_[-1:1:6j, [0]*3, 5, 6]
|
||||
array([-1. , -0.6, -0.2, 0.2, 0.6, 1. , 0. , 0. , 0. , 5. , 6. ])
|
||||
|
||||
String integers specify the axis to concatenate along or the minimum
|
||||
number of dimensions to force entries into.
|
||||
|
||||
>>> a = np.array([[0, 1, 2], [3, 4, 5]])
|
||||
>>> np.r_['-1', a, a] # concatenate along last axis
|
||||
array([[0, 1, 2, 0, 1, 2],
|
||||
[3, 4, 5, 3, 4, 5]])
|
||||
>>> np.r_['0,2', [1,2,3], [4,5,6]] # concatenate along first axis, dim>=2
|
||||
array([[1, 2, 3],
|
||||
[4, 5, 6]])
|
||||
|
||||
>>> np.r_['0,2,0', [1,2,3], [4,5,6]]
|
||||
array([[1],
|
||||
[2],
|
||||
[3],
|
||||
[4],
|
||||
[5],
|
||||
[6]])
|
||||
>>> np.r_['1,2,0', [1,2,3], [4,5,6]]
|
||||
array([[1, 4],
|
||||
[2, 5],
|
||||
[3, 6]])
|
||||
|
||||
Using 'r' or 'c' as a first string argument creates a matrix.
|
||||
|
||||
>>> np.r_['r',[1,2,3], [4,5,6]]
|
||||
matrix([[1, 2, 3, 4, 5, 6]])
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
AxisConcatenator.__init__(self, 0)
|
||||
|
||||
r_ = RClass()
|
||||
|
||||
class CClass(AxisConcatenator):
|
||||
"""
|
||||
Translates slice objects to concatenation along the second axis.
|
||||
|
||||
This is short-hand for ``np.r_['-1,2,0', index expression]``, which is
|
||||
useful because of its common occurrence. In particular, arrays will be
|
||||
stacked along their last axis after being upgraded to at least 2-D with
|
||||
1's post-pended to the shape (column vectors made out of 1-D arrays).
|
||||
|
||||
See Also
|
||||
--------
|
||||
column_stack : Stack 1-D arrays as columns into a 2-D array.
|
||||
r_ : For more detailed documentation.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.c_[np.array([1,2,3]), np.array([4,5,6])]
|
||||
array([[1, 4],
|
||||
[2, 5],
|
||||
[3, 6]])
|
||||
>>> np.c_[np.array([[1,2,3]]), 0, 0, np.array([[4,5,6]])]
|
||||
array([[1, 2, 3, 0, 0, 4, 5, 6]])
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
AxisConcatenator.__init__(self, -1, ndmin=2, trans1d=0)
|
||||
|
||||
|
||||
c_ = CClass()
|
||||
|
||||
|
||||
@set_module('numpy')
|
||||
class ndenumerate(object):
|
||||
"""
|
||||
Multidimensional index iterator.
|
||||
|
||||
Return an iterator yielding pairs of array coordinates and values.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arr : ndarray
|
||||
Input array.
|
||||
|
||||
See Also
|
||||
--------
|
||||
ndindex, flatiter
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> a = np.array([[1, 2], [3, 4]])
|
||||
>>> for index, x in np.ndenumerate(a):
|
||||
... print(index, x)
|
||||
(0, 0) 1
|
||||
(0, 1) 2
|
||||
(1, 0) 3
|
||||
(1, 1) 4
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, arr):
|
||||
self.iter = asarray(arr).flat
|
||||
|
||||
def __next__(self):
|
||||
"""
|
||||
Standard iterator method, returns the index tuple and array value.
|
||||
|
||||
Returns
|
||||
-------
|
||||
coords : tuple of ints
|
||||
The indices of the current iteration.
|
||||
val : scalar
|
||||
The array element of the current iteration.
|
||||
|
||||
"""
|
||||
return self.iter.coords, next(self.iter)
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
next = __next__
|
||||
|
||||
|
||||
@set_module('numpy')
|
||||
class ndindex(object):
|
||||
"""
|
||||
An N-dimensional iterator object to index arrays.
|
||||
|
||||
Given the shape of an array, an `ndindex` instance iterates over
|
||||
the N-dimensional index of the array. At each iteration a tuple
|
||||
of indices is returned, the last dimension is iterated over first.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
`*args` : ints
|
||||
The size of each dimension of the array.
|
||||
|
||||
See Also
|
||||
--------
|
||||
ndenumerate, flatiter
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> for index in np.ndindex(3, 2, 1):
|
||||
... print(index)
|
||||
(0, 0, 0)
|
||||
(0, 1, 0)
|
||||
(1, 0, 0)
|
||||
(1, 1, 0)
|
||||
(2, 0, 0)
|
||||
(2, 1, 0)
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *shape):
|
||||
if len(shape) == 1 and isinstance(shape[0], tuple):
|
||||
shape = shape[0]
|
||||
x = as_strided(_nx.zeros(1), shape=shape,
|
||||
strides=_nx.zeros_like(shape))
|
||||
self._it = _nx.nditer(x, flags=['multi_index', 'zerosize_ok'],
|
||||
order='C')
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def ndincr(self):
|
||||
"""
|
||||
Increment the multi-dimensional index by one.
|
||||
|
||||
This method is for backward compatibility only: do not use.
|
||||
"""
|
||||
next(self)
|
||||
|
||||
def __next__(self):
|
||||
"""
|
||||
Standard iterator method, updates the index and returns the index
|
||||
tuple.
|
||||
|
||||
Returns
|
||||
-------
|
||||
val : tuple of ints
|
||||
Returns a tuple containing the indices of the current
|
||||
iteration.
|
||||
|
||||
"""
|
||||
next(self._it)
|
||||
return self._it.multi_index
|
||||
|
||||
next = __next__
|
||||
|
||||
|
||||
# You can do all this with slice() plus a few special objects,
|
||||
# but there's a lot to remember. This version is simpler because
|
||||
# it uses the standard array indexing syntax.
|
||||
#
|
||||
# Written by Konrad Hinsen <hinsen@cnrs-orleans.fr>
|
||||
# last revision: 1999-7-23
|
||||
#
|
||||
# Cosmetic changes by T. Oliphant 2001
|
||||
#
|
||||
#
|
||||
|
||||
class IndexExpression(object):
|
||||
"""
|
||||
A nicer way to build up index tuples for arrays.
|
||||
|
||||
.. note::
|
||||
Use one of the two predefined instances `index_exp` or `s_`
|
||||
rather than directly using `IndexExpression`.
|
||||
|
||||
For any index combination, including slicing and axis insertion,
|
||||
``a[indices]`` is the same as ``a[np.index_exp[indices]]`` for any
|
||||
array `a`. However, ``np.index_exp[indices]`` can be used anywhere
|
||||
in Python code and returns a tuple of slice objects that can be
|
||||
used in the construction of complex index expressions.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
maketuple : bool
|
||||
If True, always returns a tuple.
|
||||
|
||||
See Also
|
||||
--------
|
||||
index_exp : Predefined instance that always returns a tuple:
|
||||
`index_exp = IndexExpression(maketuple=True)`.
|
||||
s_ : Predefined instance without tuple conversion:
|
||||
`s_ = IndexExpression(maketuple=False)`.
|
||||
|
||||
Notes
|
||||
-----
|
||||
You can do all this with `slice()` plus a few special objects,
|
||||
but there's a lot to remember and this version is simpler because
|
||||
it uses the standard array indexing syntax.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.s_[2::2]
|
||||
slice(2, None, 2)
|
||||
>>> np.index_exp[2::2]
|
||||
(slice(2, None, 2),)
|
||||
|
||||
>>> np.array([0, 1, 2, 3, 4])[np.s_[2::2]]
|
||||
array([2, 4])
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, maketuple):
|
||||
self.maketuple = maketuple
|
||||
|
||||
def __getitem__(self, item):
|
||||
if self.maketuple and not isinstance(item, tuple):
|
||||
return (item,)
|
||||
else:
|
||||
return item
|
||||
|
||||
index_exp = IndexExpression(maketuple=True)
|
||||
s_ = IndexExpression(maketuple=False)
|
||||
|
||||
# End contribution from Konrad.
|
||||
|
||||
|
||||
# The following functions complement those in twodim_base, but are
|
||||
# applicable to N-dimensions.
|
||||
|
||||
|
||||
def _fill_diagonal_dispatcher(a, val, wrap=None):
|
||||
return (a,)
|
||||
|
||||
|
||||
@array_function_dispatch(_fill_diagonal_dispatcher)
|
||||
def fill_diagonal(a, val, wrap=False):
|
||||
"""Fill the main diagonal of the given array of any dimensionality.
|
||||
|
||||
For an array `a` with ``a.ndim >= 2``, the diagonal is the list of
|
||||
locations with indices ``a[i, ..., i]`` all identical. This function
|
||||
modifies the input array in-place, it does not return a value.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
a : array, at least 2-D.
|
||||
Array whose diagonal is to be filled, it gets modified in-place.
|
||||
|
||||
val : scalar
|
||||
Value to be written on the diagonal, its type must be compatible with
|
||||
that of the array a.
|
||||
|
||||
wrap : bool
|
||||
For tall matrices in NumPy version up to 1.6.2, the
|
||||
diagonal "wrapped" after N columns. You can have this behavior
|
||||
with this option. This affects only tall matrices.
|
||||
|
||||
See also
|
||||
--------
|
||||
diag_indices, diag_indices_from
|
||||
|
||||
Notes
|
||||
-----
|
||||
.. versionadded:: 1.4.0
|
||||
|
||||
This functionality can be obtained via `diag_indices`, but internally
|
||||
this version uses a much faster implementation that never constructs the
|
||||
indices and uses simple slicing.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> a = np.zeros((3, 3), int)
|
||||
>>> np.fill_diagonal(a, 5)
|
||||
>>> a
|
||||
array([[5, 0, 0],
|
||||
[0, 5, 0],
|
||||
[0, 0, 5]])
|
||||
|
||||
The same function can operate on a 4-D array:
|
||||
|
||||
>>> a = np.zeros((3, 3, 3, 3), int)
|
||||
>>> np.fill_diagonal(a, 4)
|
||||
|
||||
We only show a few blocks for clarity:
|
||||
|
||||
>>> a[0, 0]
|
||||
array([[4, 0, 0],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0]])
|
||||
>>> a[1, 1]
|
||||
array([[0, 0, 0],
|
||||
[0, 4, 0],
|
||||
[0, 0, 0]])
|
||||
>>> a[2, 2]
|
||||
array([[0, 0, 0],
|
||||
[0, 0, 0],
|
||||
[0, 0, 4]])
|
||||
|
||||
The wrap option affects only tall matrices:
|
||||
|
||||
>>> # tall matrices no wrap
|
||||
>>> a = np.zeros((5, 3),int)
|
||||
>>> fill_diagonal(a, 4)
|
||||
>>> a
|
||||
array([[4, 0, 0],
|
||||
[0, 4, 0],
|
||||
[0, 0, 4],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0]])
|
||||
|
||||
>>> # tall matrices wrap
|
||||
>>> a = np.zeros((5, 3),int)
|
||||
>>> fill_diagonal(a, 4, wrap=True)
|
||||
>>> a
|
||||
array([[4, 0, 0],
|
||||
[0, 4, 0],
|
||||
[0, 0, 4],
|
||||
[0, 0, 0],
|
||||
[4, 0, 0]])
|
||||
|
||||
>>> # wide matrices
|
||||
>>> a = np.zeros((3, 5),int)
|
||||
>>> fill_diagonal(a, 4, wrap=True)
|
||||
>>> a
|
||||
array([[4, 0, 0, 0, 0],
|
||||
[0, 4, 0, 0, 0],
|
||||
[0, 0, 4, 0, 0]])
|
||||
|
||||
"""
|
||||
if a.ndim < 2:
|
||||
raise ValueError("array must be at least 2-d")
|
||||
end = None
|
||||
if a.ndim == 2:
|
||||
# Explicit, fast formula for the common case. For 2-d arrays, we
|
||||
# accept rectangular ones.
|
||||
step = a.shape[1] + 1
|
||||
#This is needed to don't have tall matrix have the diagonal wrap.
|
||||
if not wrap:
|
||||
end = a.shape[1] * a.shape[1]
|
||||
else:
|
||||
# For more than d=2, the strided formula is only valid for arrays with
|
||||
# all dimensions equal, so we check first.
|
||||
if not alltrue(diff(a.shape) == 0):
|
||||
raise ValueError("All dimensions of input must be of equal length")
|
||||
step = 1 + (cumprod(a.shape[:-1])).sum()
|
||||
|
||||
# Write the value out into the diagonal.
|
||||
a.flat[:end:step] = val
|
||||
|
||||
|
||||
@set_module('numpy')
|
||||
def diag_indices(n, ndim=2):
|
||||
"""
|
||||
Return the indices to access the main diagonal of an array.
|
||||
|
||||
This returns a tuple of indices that can be used to access the main
|
||||
diagonal of an array `a` with ``a.ndim >= 2`` dimensions and shape
|
||||
(n, n, ..., n). For ``a.ndim = 2`` this is the usual diagonal, for
|
||||
``a.ndim > 2`` this is the set of indices to access ``a[i, i, ..., i]``
|
||||
for ``i = [0..n-1]``.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
n : int
|
||||
The size, along each dimension, of the arrays for which the returned
|
||||
indices can be used.
|
||||
|
||||
ndim : int, optional
|
||||
The number of dimensions.
|
||||
|
||||
See also
|
||||
--------
|
||||
diag_indices_from
|
||||
|
||||
Notes
|
||||
-----
|
||||
.. versionadded:: 1.4.0
|
||||
|
||||
Examples
|
||||
--------
|
||||
Create a set of indices to access the diagonal of a (4, 4) array:
|
||||
|
||||
>>> di = np.diag_indices(4)
|
||||
>>> di
|
||||
(array([0, 1, 2, 3]), array([0, 1, 2, 3]))
|
||||
>>> a = np.arange(16).reshape(4, 4)
|
||||
>>> a
|
||||
array([[ 0, 1, 2, 3],
|
||||
[ 4, 5, 6, 7],
|
||||
[ 8, 9, 10, 11],
|
||||
[12, 13, 14, 15]])
|
||||
>>> a[di] = 100
|
||||
>>> a
|
||||
array([[100, 1, 2, 3],
|
||||
[ 4, 100, 6, 7],
|
||||
[ 8, 9, 100, 11],
|
||||
[ 12, 13, 14, 100]])
|
||||
|
||||
Now, we create indices to manipulate a 3-D array:
|
||||
|
||||
>>> d3 = np.diag_indices(2, 3)
|
||||
>>> d3
|
||||
(array([0, 1]), array([0, 1]), array([0, 1]))
|
||||
|
||||
And use it to set the diagonal of an array of zeros to 1:
|
||||
|
||||
>>> a = np.zeros((2, 2, 2), dtype=int)
|
||||
>>> a[d3] = 1
|
||||
>>> a
|
||||
array([[[1, 0],
|
||||
[0, 0]],
|
||||
[[0, 0],
|
||||
[0, 1]]])
|
||||
|
||||
"""
|
||||
idx = arange(n)
|
||||
return (idx,) * ndim
|
||||
|
||||
|
||||
def _diag_indices_from(arr):
|
||||
return (arr,)
|
||||
|
||||
|
||||
@array_function_dispatch(_diag_indices_from)
|
||||
def diag_indices_from(arr):
|
||||
"""
|
||||
Return the indices to access the main diagonal of an n-dimensional array.
|
||||
|
||||
See `diag_indices` for full details.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arr : array, at least 2-D
|
||||
|
||||
See Also
|
||||
--------
|
||||
diag_indices
|
||||
|
||||
Notes
|
||||
-----
|
||||
.. versionadded:: 1.4.0
|
||||
|
||||
"""
|
||||
|
||||
if not arr.ndim >= 2:
|
||||
raise ValueError("input array must be at least 2-d")
|
||||
# For more than d=2, the strided formula is only valid for arrays with
|
||||
# all dimensions equal, so we check first.
|
||||
if not alltrue(diff(arr.shape) == 0):
|
||||
raise ValueError("All dimensions of input must be of equal length")
|
||||
|
||||
return diag_indices(arr.shape[0], arr.ndim)
|
||||
@@ -0,0 +1,160 @@
|
||||
"""
|
||||
Basic functions used by several sub-packages and
|
||||
useful to have in the main name-space.
|
||||
|
||||
Type Handling
|
||||
-------------
|
||||
================ ===================
|
||||
iscomplexobj Test for complex object, scalar result
|
||||
isrealobj Test for real object, scalar result
|
||||
iscomplex Test for complex elements, array result
|
||||
isreal Test for real elements, array result
|
||||
imag Imaginary part
|
||||
real Real part
|
||||
real_if_close Turns complex number with tiny imaginary part to real
|
||||
isneginf Tests for negative infinity, array result
|
||||
isposinf Tests for positive infinity, array result
|
||||
isnan Tests for nans, array result
|
||||
isinf Tests for infinity, array result
|
||||
isfinite Tests for finite numbers, array result
|
||||
isscalar True if argument is a scalar
|
||||
nan_to_num Replaces NaN's with 0 and infinities with large numbers
|
||||
cast Dictionary of functions to force cast to each type
|
||||
common_type Determine the minimum common type code for a group
|
||||
of arrays
|
||||
mintypecode Return minimal allowed common typecode.
|
||||
================ ===================
|
||||
|
||||
Index Tricks
|
||||
------------
|
||||
================ ===================
|
||||
mgrid Method which allows easy construction of N-d
|
||||
'mesh-grids'
|
||||
``r_`` Append and construct arrays: turns slice objects into
|
||||
ranges and concatenates them, for 2d arrays appends rows.
|
||||
index_exp Konrad Hinsen's index_expression class instance which
|
||||
can be useful for building complicated slicing syntax.
|
||||
================ ===================
|
||||
|
||||
Useful Functions
|
||||
----------------
|
||||
================ ===================
|
||||
select Extension of where to multiple conditions and choices
|
||||
extract Extract 1d array from flattened array according to mask
|
||||
insert Insert 1d array of values into Nd array according to mask
|
||||
linspace Evenly spaced samples in linear space
|
||||
logspace Evenly spaced samples in logarithmic space
|
||||
fix Round x to nearest integer towards zero
|
||||
mod Modulo mod(x,y) = x % y except keeps sign of y
|
||||
amax Array maximum along axis
|
||||
amin Array minimum along axis
|
||||
ptp Array max-min along axis
|
||||
cumsum Cumulative sum along axis
|
||||
prod Product of elements along axis
|
||||
cumprod Cumluative product along axis
|
||||
diff Discrete differences along axis
|
||||
angle Returns angle of complex argument
|
||||
unwrap Unwrap phase along given axis (1-d algorithm)
|
||||
sort_complex Sort a complex-array (based on real, then imaginary)
|
||||
trim_zeros Trim the leading and trailing zeros from 1D array.
|
||||
vectorize A class that wraps a Python function taking scalar
|
||||
arguments into a generalized function which can handle
|
||||
arrays of arguments using the broadcast rules of
|
||||
numerix Python.
|
||||
================ ===================
|
||||
|
||||
Shape Manipulation
|
||||
------------------
|
||||
================ ===================
|
||||
squeeze Return a with length-one dimensions removed.
|
||||
atleast_1d Force arrays to be >= 1D
|
||||
atleast_2d Force arrays to be >= 2D
|
||||
atleast_3d Force arrays to be >= 3D
|
||||
vstack Stack arrays vertically (row on row)
|
||||
hstack Stack arrays horizontally (column on column)
|
||||
column_stack Stack 1D arrays as columns into 2D array
|
||||
dstack Stack arrays depthwise (along third dimension)
|
||||
stack Stack arrays along a new axis
|
||||
split Divide array into a list of sub-arrays
|
||||
hsplit Split into columns
|
||||
vsplit Split into rows
|
||||
dsplit Split along third dimension
|
||||
================ ===================
|
||||
|
||||
Matrix (2D Array) Manipulations
|
||||
-------------------------------
|
||||
================ ===================
|
||||
fliplr 2D array with columns flipped
|
||||
flipud 2D array with rows flipped
|
||||
rot90 Rotate a 2D array a multiple of 90 degrees
|
||||
eye Return a 2D array with ones down a given diagonal
|
||||
diag Construct a 2D array from a vector, or return a given
|
||||
diagonal from a 2D array.
|
||||
mat Construct a Matrix
|
||||
bmat Build a Matrix from blocks
|
||||
================ ===================
|
||||
|
||||
Polynomials
|
||||
-----------
|
||||
================ ===================
|
||||
poly1d A one-dimensional polynomial class
|
||||
poly Return polynomial coefficients from roots
|
||||
roots Find roots of polynomial given coefficients
|
||||
polyint Integrate polynomial
|
||||
polyder Differentiate polynomial
|
||||
polyadd Add polynomials
|
||||
polysub Subtract polynomials
|
||||
polymul Multiply polynomials
|
||||
polydiv Divide polynomials
|
||||
polyval Evaluate polynomial at given argument
|
||||
================ ===================
|
||||
|
||||
Iterators
|
||||
---------
|
||||
================ ===================
|
||||
Arrayterator A buffered iterator for big arrays.
|
||||
================ ===================
|
||||
|
||||
Import Tricks
|
||||
-------------
|
||||
================ ===================
|
||||
ppimport Postpone module import until trying to use it
|
||||
ppimport_attr Postpone module import until trying to use its attribute
|
||||
ppresolve Import postponed module and return it.
|
||||
================ ===================
|
||||
|
||||
Machine Arithmetics
|
||||
-------------------
|
||||
================ ===================
|
||||
machar_single Single precision floating point arithmetic parameters
|
||||
machar_double Double precision floating point arithmetic parameters
|
||||
================ ===================
|
||||
|
||||
Threading Tricks
|
||||
----------------
|
||||
================ ===================
|
||||
ParallelExec Execute commands in parallel thread.
|
||||
================ ===================
|
||||
|
||||
Array Set Operations
|
||||
-----------------------
|
||||
Set operations for numeric arrays based on sort() function.
|
||||
|
||||
================ ===================
|
||||
unique Unique elements of an array.
|
||||
isin Test whether each element of an ND array is present
|
||||
anywhere within a second array.
|
||||
ediff1d Array difference (auxiliary function).
|
||||
intersect1d Intersection of 1D arrays with unique elements.
|
||||
setxor1d Set exclusive-or of 1D arrays with unique elements.
|
||||
in1d Test whether elements in a 1D array are also present in
|
||||
another array.
|
||||
union1d Union of 1D arrays with unique elements.
|
||||
setdiff1d Set difference of 1D arrays with unique elements.
|
||||
================ ===================
|
||||
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
depends = ['core', 'testing']
|
||||
global_symbols = ['*']
|
||||
@@ -0,0 +1,182 @@
|
||||
"""Mixin classes for custom array types that don't inherit from ndarray."""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import sys
|
||||
|
||||
from numpy.core import umath as um
|
||||
|
||||
# Nothing should be exposed in the top-level NumPy module.
|
||||
__all__ = []
|
||||
|
||||
|
||||
def _disables_array_ufunc(obj):
|
||||
"""True when __array_ufunc__ is set to None."""
|
||||
try:
|
||||
return obj.__array_ufunc__ is None
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
|
||||
def _binary_method(ufunc, name):
|
||||
"""Implement a forward binary method with a ufunc, e.g., __add__."""
|
||||
def func(self, other):
|
||||
if _disables_array_ufunc(other):
|
||||
return NotImplemented
|
||||
return ufunc(self, other)
|
||||
func.__name__ = '__{}__'.format(name)
|
||||
return func
|
||||
|
||||
|
||||
def _reflected_binary_method(ufunc, name):
|
||||
"""Implement a reflected binary method with a ufunc, e.g., __radd__."""
|
||||
def func(self, other):
|
||||
if _disables_array_ufunc(other):
|
||||
return NotImplemented
|
||||
return ufunc(other, self)
|
||||
func.__name__ = '__r{}__'.format(name)
|
||||
return func
|
||||
|
||||
|
||||
def _inplace_binary_method(ufunc, name):
|
||||
"""Implement an in-place binary method with a ufunc, e.g., __iadd__."""
|
||||
def func(self, other):
|
||||
return ufunc(self, other, out=(self,))
|
||||
func.__name__ = '__i{}__'.format(name)
|
||||
return func
|
||||
|
||||
|
||||
def _numeric_methods(ufunc, name):
|
||||
"""Implement forward, reflected and inplace binary methods with a ufunc."""
|
||||
return (_binary_method(ufunc, name),
|
||||
_reflected_binary_method(ufunc, name),
|
||||
_inplace_binary_method(ufunc, name))
|
||||
|
||||
|
||||
def _unary_method(ufunc, name):
|
||||
"""Implement a unary special method with a ufunc."""
|
||||
def func(self):
|
||||
return ufunc(self)
|
||||
func.__name__ = '__{}__'.format(name)
|
||||
return func
|
||||
|
||||
|
||||
class NDArrayOperatorsMixin(object):
|
||||
"""Mixin defining all operator special methods using __array_ufunc__.
|
||||
|
||||
This class implements the special methods for almost all of Python's
|
||||
builtin operators defined in the `operator` module, including comparisons
|
||||
(``==``, ``>``, etc.) and arithmetic (``+``, ``*``, ``-``, etc.), by
|
||||
deferring to the ``__array_ufunc__`` method, which subclasses must
|
||||
implement.
|
||||
|
||||
It is useful for writing classes that do not inherit from `numpy.ndarray`,
|
||||
but that should support arithmetic and numpy universal functions like
|
||||
arrays as described in `A Mechanism for Overriding Ufuncs
|
||||
<../../neps/nep-0013-ufunc-overrides.html>`_.
|
||||
|
||||
As an trivial example, consider this implementation of an ``ArrayLike``
|
||||
class that simply wraps a NumPy array and ensures that the result of any
|
||||
arithmetic operation is also an ``ArrayLike`` object::
|
||||
|
||||
class ArrayLike(np.lib.mixins.NDArrayOperatorsMixin):
|
||||
def __init__(self, value):
|
||||
self.value = np.asarray(value)
|
||||
|
||||
# One might also consider adding the built-in list type to this
|
||||
# list, to support operations like np.add(array_like, list)
|
||||
_HANDLED_TYPES = (np.ndarray, numbers.Number)
|
||||
|
||||
def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
|
||||
out = kwargs.get('out', ())
|
||||
for x in inputs + out:
|
||||
# Only support operations with instances of _HANDLED_TYPES.
|
||||
# Use ArrayLike instead of type(self) for isinstance to
|
||||
# allow subclasses that don't override __array_ufunc__ to
|
||||
# handle ArrayLike objects.
|
||||
if not isinstance(x, self._HANDLED_TYPES + (ArrayLike,)):
|
||||
return NotImplemented
|
||||
|
||||
# Defer to the implementation of the ufunc on unwrapped values.
|
||||
inputs = tuple(x.value if isinstance(x, ArrayLike) else x
|
||||
for x in inputs)
|
||||
if out:
|
||||
kwargs['out'] = tuple(
|
||||
x.value if isinstance(x, ArrayLike) else x
|
||||
for x in out)
|
||||
result = getattr(ufunc, method)(*inputs, **kwargs)
|
||||
|
||||
if type(result) is tuple:
|
||||
# multiple return values
|
||||
return tuple(type(self)(x) for x in result)
|
||||
elif method == 'at':
|
||||
# no return value
|
||||
return None
|
||||
else:
|
||||
# one return value
|
||||
return type(self)(result)
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r)' % (type(self).__name__, self.value)
|
||||
|
||||
In interactions between ``ArrayLike`` objects and numbers or numpy arrays,
|
||||
the result is always another ``ArrayLike``:
|
||||
|
||||
>>> x = ArrayLike([1, 2, 3])
|
||||
>>> x - 1
|
||||
ArrayLike(array([0, 1, 2]))
|
||||
>>> 1 - x
|
||||
ArrayLike(array([ 0, -1, -2]))
|
||||
>>> np.arange(3) - x
|
||||
ArrayLike(array([-1, -1, -1]))
|
||||
>>> x - np.arange(3)
|
||||
ArrayLike(array([1, 1, 1]))
|
||||
|
||||
Note that unlike ``numpy.ndarray``, ``ArrayLike`` does not allow operations
|
||||
with arbitrary, unrecognized types. This ensures that interactions with
|
||||
ArrayLike preserve a well-defined casting hierarchy.
|
||||
|
||||
.. versionadded:: 1.13
|
||||
"""
|
||||
# Like np.ndarray, this mixin class implements "Option 1" from the ufunc
|
||||
# overrides NEP.
|
||||
|
||||
# comparisons don't have reflected and in-place versions
|
||||
__lt__ = _binary_method(um.less, 'lt')
|
||||
__le__ = _binary_method(um.less_equal, 'le')
|
||||
__eq__ = _binary_method(um.equal, 'eq')
|
||||
__ne__ = _binary_method(um.not_equal, 'ne')
|
||||
__gt__ = _binary_method(um.greater, 'gt')
|
||||
__ge__ = _binary_method(um.greater_equal, 'ge')
|
||||
|
||||
# numeric methods
|
||||
__add__, __radd__, __iadd__ = _numeric_methods(um.add, 'add')
|
||||
__sub__, __rsub__, __isub__ = _numeric_methods(um.subtract, 'sub')
|
||||
__mul__, __rmul__, __imul__ = _numeric_methods(um.multiply, 'mul')
|
||||
__matmul__, __rmatmul__, __imatmul__ = _numeric_methods(
|
||||
um.matmul, 'matmul')
|
||||
if sys.version_info.major < 3:
|
||||
# Python 3 uses only __truediv__ and __floordiv__
|
||||
__div__, __rdiv__, __idiv__ = _numeric_methods(um.divide, 'div')
|
||||
__truediv__, __rtruediv__, __itruediv__ = _numeric_methods(
|
||||
um.true_divide, 'truediv')
|
||||
__floordiv__, __rfloordiv__, __ifloordiv__ = _numeric_methods(
|
||||
um.floor_divide, 'floordiv')
|
||||
__mod__, __rmod__, __imod__ = _numeric_methods(um.remainder, 'mod')
|
||||
__divmod__ = _binary_method(um.divmod, 'divmod')
|
||||
__rdivmod__ = _reflected_binary_method(um.divmod, 'divmod')
|
||||
# __idivmod__ does not exist
|
||||
# TODO: handle the optional third argument for __pow__?
|
||||
__pow__, __rpow__, __ipow__ = _numeric_methods(um.power, 'pow')
|
||||
__lshift__, __rlshift__, __ilshift__ = _numeric_methods(
|
||||
um.left_shift, 'lshift')
|
||||
__rshift__, __rrshift__, __irshift__ = _numeric_methods(
|
||||
um.right_shift, 'rshift')
|
||||
__and__, __rand__, __iand__ = _numeric_methods(um.bitwise_and, 'and')
|
||||
__xor__, __rxor__, __ixor__ = _numeric_methods(um.bitwise_xor, 'xor')
|
||||
__or__, __ror__, __ior__ = _numeric_methods(um.bitwise_or, 'or')
|
||||
|
||||
# unary methods
|
||||
__neg__ = _unary_method(um.negative, 'neg')
|
||||
__pos__ = _unary_method(um.positive, 'pos')
|
||||
__abs__ = _unary_method(um.absolute, 'abs')
|
||||
__invert__ = _unary_method(um.invert, 'invert')
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,600 @@
|
||||
"""
|
||||
Wrapper functions to more user-friendly calling of certain math functions
|
||||
whose output data-type is different than the input data-type in certain
|
||||
domains of the input.
|
||||
|
||||
For example, for functions like `log` with branch cuts, the versions in this
|
||||
module provide the mathematically valid answers in the complex plane::
|
||||
|
||||
>>> import math
|
||||
>>> from numpy.lib import scimath
|
||||
>>> scimath.log(-math.exp(1)) == (1+1j*math.pi)
|
||||
True
|
||||
|
||||
Similarly, `sqrt`, other base logarithms, `power` and trig functions are
|
||||
correctly handled. See their respective docstrings for specific examples.
|
||||
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import numpy.core.numeric as nx
|
||||
import numpy.core.numerictypes as nt
|
||||
from numpy.core.numeric import asarray, any
|
||||
from numpy.core.overrides import array_function_dispatch
|
||||
from numpy.lib.type_check import isreal
|
||||
|
||||
|
||||
__all__ = [
|
||||
'sqrt', 'log', 'log2', 'logn', 'log10', 'power', 'arccos', 'arcsin',
|
||||
'arctanh'
|
||||
]
|
||||
|
||||
|
||||
_ln2 = nx.log(2.0)
|
||||
|
||||
|
||||
def _tocomplex(arr):
|
||||
"""Convert its input `arr` to a complex array.
|
||||
|
||||
The input is returned as a complex array of the smallest type that will fit
|
||||
the original data: types like single, byte, short, etc. become csingle,
|
||||
while others become cdouble.
|
||||
|
||||
A copy of the input is always made.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arr : array
|
||||
|
||||
Returns
|
||||
-------
|
||||
array
|
||||
An array with the same input data as the input but in complex form.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
First, consider an input of type short:
|
||||
|
||||
>>> a = np.array([1,2,3],np.short)
|
||||
|
||||
>>> ac = np.lib.scimath._tocomplex(a); ac
|
||||
array([ 1.+0.j, 2.+0.j, 3.+0.j], dtype=complex64)
|
||||
|
||||
>>> ac.dtype
|
||||
dtype('complex64')
|
||||
|
||||
If the input is of type double, the output is correspondingly of the
|
||||
complex double type as well:
|
||||
|
||||
>>> b = np.array([1,2,3],np.double)
|
||||
|
||||
>>> bc = np.lib.scimath._tocomplex(b); bc
|
||||
array([ 1.+0.j, 2.+0.j, 3.+0.j])
|
||||
|
||||
>>> bc.dtype
|
||||
dtype('complex128')
|
||||
|
||||
Note that even if the input was complex to begin with, a copy is still
|
||||
made, since the astype() method always copies:
|
||||
|
||||
>>> c = np.array([1,2,3],np.csingle)
|
||||
|
||||
>>> cc = np.lib.scimath._tocomplex(c); cc
|
||||
array([ 1.+0.j, 2.+0.j, 3.+0.j], dtype=complex64)
|
||||
|
||||
>>> c *= 2; c
|
||||
array([ 2.+0.j, 4.+0.j, 6.+0.j], dtype=complex64)
|
||||
|
||||
>>> cc
|
||||
array([ 1.+0.j, 2.+0.j, 3.+0.j], dtype=complex64)
|
||||
"""
|
||||
if issubclass(arr.dtype.type, (nt.single, nt.byte, nt.short, nt.ubyte,
|
||||
nt.ushort, nt.csingle)):
|
||||
return arr.astype(nt.csingle)
|
||||
else:
|
||||
return arr.astype(nt.cdouble)
|
||||
|
||||
|
||||
def _fix_real_lt_zero(x):
|
||||
"""Convert `x` to complex if it has real, negative components.
|
||||
|
||||
Otherwise, output is just the array version of the input (via asarray).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like
|
||||
|
||||
Returns
|
||||
-------
|
||||
array
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.lib.scimath._fix_real_lt_zero([1,2])
|
||||
array([1, 2])
|
||||
|
||||
>>> np.lib.scimath._fix_real_lt_zero([-1,2])
|
||||
array([-1.+0.j, 2.+0.j])
|
||||
|
||||
"""
|
||||
x = asarray(x)
|
||||
if any(isreal(x) & (x < 0)):
|
||||
x = _tocomplex(x)
|
||||
return x
|
||||
|
||||
|
||||
def _fix_int_lt_zero(x):
|
||||
"""Convert `x` to double if it has real, negative components.
|
||||
|
||||
Otherwise, output is just the array version of the input (via asarray).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like
|
||||
|
||||
Returns
|
||||
-------
|
||||
array
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.lib.scimath._fix_int_lt_zero([1,2])
|
||||
array([1, 2])
|
||||
|
||||
>>> np.lib.scimath._fix_int_lt_zero([-1,2])
|
||||
array([-1., 2.])
|
||||
"""
|
||||
x = asarray(x)
|
||||
if any(isreal(x) & (x < 0)):
|
||||
x = x * 1.0
|
||||
return x
|
||||
|
||||
|
||||
def _fix_real_abs_gt_1(x):
|
||||
"""Convert `x` to complex if it has real components x_i with abs(x_i)>1.
|
||||
|
||||
Otherwise, output is just the array version of the input (via asarray).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like
|
||||
|
||||
Returns
|
||||
-------
|
||||
array
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.lib.scimath._fix_real_abs_gt_1([0,1])
|
||||
array([0, 1])
|
||||
|
||||
>>> np.lib.scimath._fix_real_abs_gt_1([0,2])
|
||||
array([ 0.+0.j, 2.+0.j])
|
||||
"""
|
||||
x = asarray(x)
|
||||
if any(isreal(x) & (abs(x) > 1)):
|
||||
x = _tocomplex(x)
|
||||
return x
|
||||
|
||||
|
||||
def _unary_dispatcher(x):
|
||||
return (x,)
|
||||
|
||||
|
||||
@array_function_dispatch(_unary_dispatcher)
|
||||
def sqrt(x):
|
||||
"""
|
||||
Compute the square root of x.
|
||||
|
||||
For negative input elements, a complex value is returned
|
||||
(unlike `numpy.sqrt` which returns NaN).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like
|
||||
The input value(s).
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray or scalar
|
||||
The square root of `x`. If `x` was a scalar, so is `out`,
|
||||
otherwise an array is returned.
|
||||
|
||||
See Also
|
||||
--------
|
||||
numpy.sqrt
|
||||
|
||||
Examples
|
||||
--------
|
||||
For real, non-negative inputs this works just like `numpy.sqrt`:
|
||||
|
||||
>>> np.lib.scimath.sqrt(1)
|
||||
1.0
|
||||
>>> np.lib.scimath.sqrt([1, 4])
|
||||
array([ 1., 2.])
|
||||
|
||||
But it automatically handles negative inputs:
|
||||
|
||||
>>> np.lib.scimath.sqrt(-1)
|
||||
(0.0+1.0j)
|
||||
>>> np.lib.scimath.sqrt([-1,4])
|
||||
array([ 0.+1.j, 2.+0.j])
|
||||
|
||||
"""
|
||||
x = _fix_real_lt_zero(x)
|
||||
return nx.sqrt(x)
|
||||
|
||||
|
||||
@array_function_dispatch(_unary_dispatcher)
|
||||
def log(x):
|
||||
"""
|
||||
Compute the natural logarithm of `x`.
|
||||
|
||||
Return the "principal value" (for a description of this, see `numpy.log`)
|
||||
of :math:`log_e(x)`. For real `x > 0`, this is a real number (``log(0)``
|
||||
returns ``-inf`` and ``log(np.inf)`` returns ``inf``). Otherwise, the
|
||||
complex principle value is returned.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like
|
||||
The value(s) whose log is (are) required.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray or scalar
|
||||
The log of the `x` value(s). If `x` was a scalar, so is `out`,
|
||||
otherwise an array is returned.
|
||||
|
||||
See Also
|
||||
--------
|
||||
numpy.log
|
||||
|
||||
Notes
|
||||
-----
|
||||
For a log() that returns ``NAN`` when real `x < 0`, use `numpy.log`
|
||||
(note, however, that otherwise `numpy.log` and this `log` are identical,
|
||||
i.e., both return ``-inf`` for `x = 0`, ``inf`` for `x = inf`, and,
|
||||
notably, the complex principle value if ``x.imag != 0``).
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.emath.log(np.exp(1))
|
||||
1.0
|
||||
|
||||
Negative arguments are handled "correctly" (recall that
|
||||
``exp(log(x)) == x`` does *not* hold for real ``x < 0``):
|
||||
|
||||
>>> np.emath.log(-np.exp(1)) == (1 + np.pi * 1j)
|
||||
True
|
||||
|
||||
"""
|
||||
x = _fix_real_lt_zero(x)
|
||||
return nx.log(x)
|
||||
|
||||
|
||||
@array_function_dispatch(_unary_dispatcher)
|
||||
def log10(x):
|
||||
"""
|
||||
Compute the logarithm base 10 of `x`.
|
||||
|
||||
Return the "principal value" (for a description of this, see
|
||||
`numpy.log10`) of :math:`log_{10}(x)`. For real `x > 0`, this
|
||||
is a real number (``log10(0)`` returns ``-inf`` and ``log10(np.inf)``
|
||||
returns ``inf``). Otherwise, the complex principle value is returned.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like or scalar
|
||||
The value(s) whose log base 10 is (are) required.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray or scalar
|
||||
The log base 10 of the `x` value(s). If `x` was a scalar, so is `out`,
|
||||
otherwise an array object is returned.
|
||||
|
||||
See Also
|
||||
--------
|
||||
numpy.log10
|
||||
|
||||
Notes
|
||||
-----
|
||||
For a log10() that returns ``NAN`` when real `x < 0`, use `numpy.log10`
|
||||
(note, however, that otherwise `numpy.log10` and this `log10` are
|
||||
identical, i.e., both return ``-inf`` for `x = 0`, ``inf`` for `x = inf`,
|
||||
and, notably, the complex principle value if ``x.imag != 0``).
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
(We set the printing precision so the example can be auto-tested)
|
||||
|
||||
>>> np.set_printoptions(precision=4)
|
||||
|
||||
>>> np.emath.log10(10**1)
|
||||
1.0
|
||||
|
||||
>>> np.emath.log10([-10**1, -10**2, 10**2])
|
||||
array([ 1.+1.3644j, 2.+1.3644j, 2.+0.j ])
|
||||
|
||||
"""
|
||||
x = _fix_real_lt_zero(x)
|
||||
return nx.log10(x)
|
||||
|
||||
|
||||
def _logn_dispatcher(n, x):
|
||||
return (n, x,)
|
||||
|
||||
|
||||
@array_function_dispatch(_logn_dispatcher)
|
||||
def logn(n, x):
|
||||
"""
|
||||
Take log base n of x.
|
||||
|
||||
If `x` contains negative inputs, the answer is computed and returned in the
|
||||
complex domain.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
n : array_like
|
||||
The integer base(s) in which the log is taken.
|
||||
x : array_like
|
||||
The value(s) whose log base `n` is (are) required.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray or scalar
|
||||
The log base `n` of the `x` value(s). If `x` was a scalar, so is
|
||||
`out`, otherwise an array is returned.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.set_printoptions(precision=4)
|
||||
|
||||
>>> np.lib.scimath.logn(2, [4, 8])
|
||||
array([ 2., 3.])
|
||||
>>> np.lib.scimath.logn(2, [-4, -8, 8])
|
||||
array([ 2.+4.5324j, 3.+4.5324j, 3.+0.j ])
|
||||
|
||||
"""
|
||||
x = _fix_real_lt_zero(x)
|
||||
n = _fix_real_lt_zero(n)
|
||||
return nx.log(x)/nx.log(n)
|
||||
|
||||
|
||||
@array_function_dispatch(_unary_dispatcher)
|
||||
def log2(x):
|
||||
"""
|
||||
Compute the logarithm base 2 of `x`.
|
||||
|
||||
Return the "principal value" (for a description of this, see
|
||||
`numpy.log2`) of :math:`log_2(x)`. For real `x > 0`, this is
|
||||
a real number (``log2(0)`` returns ``-inf`` and ``log2(np.inf)`` returns
|
||||
``inf``). Otherwise, the complex principle value is returned.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like
|
||||
The value(s) whose log base 2 is (are) required.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray or scalar
|
||||
The log base 2 of the `x` value(s). If `x` was a scalar, so is `out`,
|
||||
otherwise an array is returned.
|
||||
|
||||
See Also
|
||||
--------
|
||||
numpy.log2
|
||||
|
||||
Notes
|
||||
-----
|
||||
For a log2() that returns ``NAN`` when real `x < 0`, use `numpy.log2`
|
||||
(note, however, that otherwise `numpy.log2` and this `log2` are
|
||||
identical, i.e., both return ``-inf`` for `x = 0`, ``inf`` for `x = inf`,
|
||||
and, notably, the complex principle value if ``x.imag != 0``).
|
||||
|
||||
Examples
|
||||
--------
|
||||
We set the printing precision so the example can be auto-tested:
|
||||
|
||||
>>> np.set_printoptions(precision=4)
|
||||
|
||||
>>> np.emath.log2(8)
|
||||
3.0
|
||||
>>> np.emath.log2([-4, -8, 8])
|
||||
array([ 2.+4.5324j, 3.+4.5324j, 3.+0.j ])
|
||||
|
||||
"""
|
||||
x = _fix_real_lt_zero(x)
|
||||
return nx.log2(x)
|
||||
|
||||
|
||||
def _power_dispatcher(x, p):
|
||||
return (x, p)
|
||||
|
||||
|
||||
@array_function_dispatch(_power_dispatcher)
|
||||
def power(x, p):
|
||||
"""
|
||||
Return x to the power p, (x**p).
|
||||
|
||||
If `x` contains negative values, the output is converted to the
|
||||
complex domain.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like
|
||||
The input value(s).
|
||||
p : array_like of ints
|
||||
The power(s) to which `x` is raised. If `x` contains multiple values,
|
||||
`p` has to either be a scalar, or contain the same number of values
|
||||
as `x`. In the latter case, the result is
|
||||
``x[0]**p[0], x[1]**p[1], ...``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray or scalar
|
||||
The result of ``x**p``. If `x` and `p` are scalars, so is `out`,
|
||||
otherwise an array is returned.
|
||||
|
||||
See Also
|
||||
--------
|
||||
numpy.power
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.set_printoptions(precision=4)
|
||||
|
||||
>>> np.lib.scimath.power([2, 4], 2)
|
||||
array([ 4, 16])
|
||||
>>> np.lib.scimath.power([2, 4], -2)
|
||||
array([ 0.25 , 0.0625])
|
||||
>>> np.lib.scimath.power([-2, 4], 2)
|
||||
array([ 4.+0.j, 16.+0.j])
|
||||
|
||||
"""
|
||||
x = _fix_real_lt_zero(x)
|
||||
p = _fix_int_lt_zero(p)
|
||||
return nx.power(x, p)
|
||||
|
||||
|
||||
@array_function_dispatch(_unary_dispatcher)
|
||||
def arccos(x):
|
||||
"""
|
||||
Compute the inverse cosine of x.
|
||||
|
||||
Return the "principal value" (for a description of this, see
|
||||
`numpy.arccos`) of the inverse cosine of `x`. For real `x` such that
|
||||
`abs(x) <= 1`, this is a real number in the closed interval
|
||||
:math:`[0, \\pi]`. Otherwise, the complex principle value is returned.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like or scalar
|
||||
The value(s) whose arccos is (are) required.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray or scalar
|
||||
The inverse cosine(s) of the `x` value(s). If `x` was a scalar, so
|
||||
is `out`, otherwise an array object is returned.
|
||||
|
||||
See Also
|
||||
--------
|
||||
numpy.arccos
|
||||
|
||||
Notes
|
||||
-----
|
||||
For an arccos() that returns ``NAN`` when real `x` is not in the
|
||||
interval ``[-1,1]``, use `numpy.arccos`.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.set_printoptions(precision=4)
|
||||
|
||||
>>> np.emath.arccos(1) # a scalar is returned
|
||||
0.0
|
||||
|
||||
>>> np.emath.arccos([1,2])
|
||||
array([ 0.-0.j , 0.+1.317j])
|
||||
|
||||
"""
|
||||
x = _fix_real_abs_gt_1(x)
|
||||
return nx.arccos(x)
|
||||
|
||||
|
||||
@array_function_dispatch(_unary_dispatcher)
|
||||
def arcsin(x):
|
||||
"""
|
||||
Compute the inverse sine of x.
|
||||
|
||||
Return the "principal value" (for a description of this, see
|
||||
`numpy.arcsin`) of the inverse sine of `x`. For real `x` such that
|
||||
`abs(x) <= 1`, this is a real number in the closed interval
|
||||
:math:`[-\\pi/2, \\pi/2]`. Otherwise, the complex principle value is
|
||||
returned.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like or scalar
|
||||
The value(s) whose arcsin is (are) required.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray or scalar
|
||||
The inverse sine(s) of the `x` value(s). If `x` was a scalar, so
|
||||
is `out`, otherwise an array object is returned.
|
||||
|
||||
See Also
|
||||
--------
|
||||
numpy.arcsin
|
||||
|
||||
Notes
|
||||
-----
|
||||
For an arcsin() that returns ``NAN`` when real `x` is not in the
|
||||
interval ``[-1,1]``, use `numpy.arcsin`.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.set_printoptions(precision=4)
|
||||
|
||||
>>> np.emath.arcsin(0)
|
||||
0.0
|
||||
|
||||
>>> np.emath.arcsin([0,1])
|
||||
array([ 0. , 1.5708])
|
||||
|
||||
"""
|
||||
x = _fix_real_abs_gt_1(x)
|
||||
return nx.arcsin(x)
|
||||
|
||||
|
||||
@array_function_dispatch(_unary_dispatcher)
|
||||
def arctanh(x):
|
||||
"""
|
||||
Compute the inverse hyperbolic tangent of `x`.
|
||||
|
||||
Return the "principal value" (for a description of this, see
|
||||
`numpy.arctanh`) of `arctanh(x)`. For real `x` such that
|
||||
`abs(x) < 1`, this is a real number. If `abs(x) > 1`, or if `x` is
|
||||
complex, the result is complex. Finally, `x = 1` returns``inf`` and
|
||||
`x=-1` returns ``-inf``.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like
|
||||
The value(s) whose arctanh is (are) required.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray or scalar
|
||||
The inverse hyperbolic tangent(s) of the `x` value(s). If `x` was
|
||||
a scalar so is `out`, otherwise an array is returned.
|
||||
|
||||
|
||||
See Also
|
||||
--------
|
||||
numpy.arctanh
|
||||
|
||||
Notes
|
||||
-----
|
||||
For an arctanh() that returns ``NAN`` when real `x` is not in the
|
||||
interval ``(-1,1)``, use `numpy.arctanh` (this latter, however, does
|
||||
return +/-inf for `x = +/-1`).
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.set_printoptions(precision=4)
|
||||
|
||||
>>> np.emath.arctanh(np.eye(2))
|
||||
array([[ Inf, 0.],
|
||||
[ 0., Inf]])
|
||||
>>> np.emath.arctanh([1j])
|
||||
array([ 0.+0.7854j])
|
||||
|
||||
"""
|
||||
x = _fix_real_abs_gt_1(x)
|
||||
return nx.arctanh(x)
|
||||
@@ -0,0 +1,12 @@
|
||||
from __future__ import division, print_function
|
||||
|
||||
def configuration(parent_package='',top_path=None):
|
||||
from numpy.distutils.misc_util import Configuration
|
||||
|
||||
config = Configuration('lib', parent_package, top_path)
|
||||
config.add_data_dir('tests')
|
||||
return config
|
||||
|
||||
if __name__ == '__main__':
|
||||
from numpy.distutils.core import setup
|
||||
setup(configuration=configuration)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,268 @@
|
||||
"""
|
||||
Utilities that manipulate strides to achieve desirable effects.
|
||||
|
||||
An explanation of strides can be found in the "ndarray.rst" file in the
|
||||
NumPy reference guide.
|
||||
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import numpy as np
|
||||
from numpy.core.overrides import array_function_dispatch
|
||||
|
||||
__all__ = ['broadcast_to', 'broadcast_arrays']
|
||||
|
||||
|
||||
class DummyArray(object):
|
||||
"""Dummy object that just exists to hang __array_interface__ dictionaries
|
||||
and possibly keep alive a reference to a base array.
|
||||
"""
|
||||
|
||||
def __init__(self, interface, base=None):
|
||||
self.__array_interface__ = interface
|
||||
self.base = base
|
||||
|
||||
|
||||
def _maybe_view_as_subclass(original_array, new_array):
|
||||
if type(original_array) is not type(new_array):
|
||||
# if input was an ndarray subclass and subclasses were OK,
|
||||
# then view the result as that subclass.
|
||||
new_array = new_array.view(type=type(original_array))
|
||||
# Since we have done something akin to a view from original_array, we
|
||||
# should let the subclass finalize (if it has it implemented, i.e., is
|
||||
# not None).
|
||||
if new_array.__array_finalize__:
|
||||
new_array.__array_finalize__(original_array)
|
||||
return new_array
|
||||
|
||||
|
||||
def as_strided(x, shape=None, strides=None, subok=False, writeable=True):
|
||||
"""
|
||||
Create a view into the array with the given shape and strides.
|
||||
|
||||
.. warning:: This function has to be used with extreme care, see notes.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : ndarray
|
||||
Array to create a new.
|
||||
shape : sequence of int, optional
|
||||
The shape of the new array. Defaults to ``x.shape``.
|
||||
strides : sequence of int, optional
|
||||
The strides of the new array. Defaults to ``x.strides``.
|
||||
subok : bool, optional
|
||||
.. versionadded:: 1.10
|
||||
|
||||
If True, subclasses are preserved.
|
||||
writeable : bool, optional
|
||||
.. versionadded:: 1.12
|
||||
|
||||
If set to False, the returned array will always be readonly.
|
||||
Otherwise it will be writable if the original array was. It
|
||||
is advisable to set this to False if possible (see Notes).
|
||||
|
||||
Returns
|
||||
-------
|
||||
view : ndarray
|
||||
|
||||
See also
|
||||
--------
|
||||
broadcast_to: broadcast an array to a given shape.
|
||||
reshape : reshape an array.
|
||||
|
||||
Notes
|
||||
-----
|
||||
``as_strided`` creates a view into the array given the exact strides
|
||||
and shape. This means it manipulates the internal data structure of
|
||||
ndarray and, if done incorrectly, the array elements can point to
|
||||
invalid memory and can corrupt results or crash your program.
|
||||
It is advisable to always use the original ``x.strides`` when
|
||||
calculating new strides to avoid reliance on a contiguous memory
|
||||
layout.
|
||||
|
||||
Furthermore, arrays created with this function often contain self
|
||||
overlapping memory, so that two elements are identical.
|
||||
Vectorized write operations on such arrays will typically be
|
||||
unpredictable. They may even give different results for small, large,
|
||||
or transposed arrays.
|
||||
Since writing to these arrays has to be tested and done with great
|
||||
care, you may want to use ``writeable=False`` to avoid accidental write
|
||||
operations.
|
||||
|
||||
For these reasons it is advisable to avoid ``as_strided`` when
|
||||
possible.
|
||||
"""
|
||||
# first convert input to array, possibly keeping subclass
|
||||
x = np.array(x, copy=False, subok=subok)
|
||||
interface = dict(x.__array_interface__)
|
||||
if shape is not None:
|
||||
interface['shape'] = tuple(shape)
|
||||
if strides is not None:
|
||||
interface['strides'] = tuple(strides)
|
||||
|
||||
array = np.asarray(DummyArray(interface, base=x))
|
||||
# The route via `__interface__` does not preserve structured
|
||||
# dtypes. Since dtype should remain unchanged, we set it explicitly.
|
||||
array.dtype = x.dtype
|
||||
|
||||
view = _maybe_view_as_subclass(x, array)
|
||||
|
||||
if view.flags.writeable and not writeable:
|
||||
view.flags.writeable = False
|
||||
|
||||
return view
|
||||
|
||||
|
||||
def _broadcast_to(array, shape, subok, readonly):
|
||||
shape = tuple(shape) if np.iterable(shape) else (shape,)
|
||||
array = np.array(array, copy=False, subok=subok)
|
||||
if not shape and array.shape:
|
||||
raise ValueError('cannot broadcast a non-scalar to a scalar array')
|
||||
if any(size < 0 for size in shape):
|
||||
raise ValueError('all elements of broadcast shape must be non-'
|
||||
'negative')
|
||||
needs_writeable = not readonly and array.flags.writeable
|
||||
extras = ['reduce_ok'] if needs_writeable else []
|
||||
op_flag = 'readwrite' if needs_writeable else 'readonly'
|
||||
it = np.nditer(
|
||||
(array,), flags=['multi_index', 'refs_ok', 'zerosize_ok'] + extras,
|
||||
op_flags=[op_flag], itershape=shape, order='C')
|
||||
with it:
|
||||
# never really has writebackifcopy semantics
|
||||
broadcast = it.itviews[0]
|
||||
result = _maybe_view_as_subclass(array, broadcast)
|
||||
if needs_writeable and not result.flags.writeable:
|
||||
result.flags.writeable = True
|
||||
return result
|
||||
|
||||
|
||||
def _broadcast_to_dispatcher(array, shape, subok=None):
|
||||
return (array,)
|
||||
|
||||
|
||||
@array_function_dispatch(_broadcast_to_dispatcher, module='numpy')
|
||||
def broadcast_to(array, shape, subok=False):
|
||||
"""Broadcast an array to a new shape.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
array : array_like
|
||||
The array to broadcast.
|
||||
shape : tuple
|
||||
The shape of the desired array.
|
||||
subok : bool, optional
|
||||
If True, then sub-classes will be passed-through, otherwise
|
||||
the returned array will be forced to be a base-class array (default).
|
||||
|
||||
Returns
|
||||
-------
|
||||
broadcast : array
|
||||
A readonly view on the original array with the given shape. It is
|
||||
typically not contiguous. Furthermore, more than one element of a
|
||||
broadcasted array may refer to a single memory location.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If the array is not compatible with the new shape according to NumPy's
|
||||
broadcasting rules.
|
||||
|
||||
Notes
|
||||
-----
|
||||
.. versionadded:: 1.10.0
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> x = np.array([1, 2, 3])
|
||||
>>> np.broadcast_to(x, (3, 3))
|
||||
array([[1, 2, 3],
|
||||
[1, 2, 3],
|
||||
[1, 2, 3]])
|
||||
"""
|
||||
return _broadcast_to(array, shape, subok=subok, readonly=True)
|
||||
|
||||
|
||||
def _broadcast_shape(*args):
|
||||
"""Returns the shape of the arrays that would result from broadcasting the
|
||||
supplied arrays against each other.
|
||||
"""
|
||||
if not args:
|
||||
return ()
|
||||
# use the old-iterator because np.nditer does not handle size 0 arrays
|
||||
# consistently
|
||||
b = np.broadcast(*args[:32])
|
||||
# unfortunately, it cannot handle 32 or more arguments directly
|
||||
for pos in range(32, len(args), 31):
|
||||
# ironically, np.broadcast does not properly handle np.broadcast
|
||||
# objects (it treats them as scalars)
|
||||
# use broadcasting to avoid allocating the full array
|
||||
b = broadcast_to(0, b.shape)
|
||||
b = np.broadcast(b, *args[pos:(pos + 31)])
|
||||
return b.shape
|
||||
|
||||
|
||||
def _broadcast_arrays_dispatcher(*args, **kwargs):
|
||||
return args
|
||||
|
||||
|
||||
@array_function_dispatch(_broadcast_arrays_dispatcher, module='numpy')
|
||||
def broadcast_arrays(*args, **kwargs):
|
||||
"""
|
||||
Broadcast any number of arrays against each other.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
`*args` : array_likes
|
||||
The arrays to broadcast.
|
||||
|
||||
subok : bool, optional
|
||||
If True, then sub-classes will be passed-through, otherwise
|
||||
the returned arrays will be forced to be a base-class array (default).
|
||||
|
||||
Returns
|
||||
-------
|
||||
broadcasted : list of arrays
|
||||
These arrays are views on the original arrays. They are typically
|
||||
not contiguous. Furthermore, more than one element of a
|
||||
broadcasted array may refer to a single memory location. If you
|
||||
need to write to the arrays, make copies first.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> x = np.array([[1,2,3]])
|
||||
>>> y = np.array([[4],[5]])
|
||||
>>> np.broadcast_arrays(x, y)
|
||||
[array([[1, 2, 3],
|
||||
[1, 2, 3]]), array([[4, 4, 4],
|
||||
[5, 5, 5]])]
|
||||
|
||||
Here is a useful idiom for getting contiguous copies instead of
|
||||
non-contiguous views.
|
||||
|
||||
>>> [np.array(a) for a in np.broadcast_arrays(x, y)]
|
||||
[array([[1, 2, 3],
|
||||
[1, 2, 3]]), array([[4, 4, 4],
|
||||
[5, 5, 5]])]
|
||||
|
||||
"""
|
||||
# nditer is not used here to avoid the limit of 32 arrays.
|
||||
# Otherwise, something like the following one-liner would suffice:
|
||||
# return np.nditer(args, flags=['multi_index', 'zerosize_ok'],
|
||||
# order='C').itviews
|
||||
|
||||
subok = kwargs.pop('subok', False)
|
||||
if kwargs:
|
||||
raise TypeError('broadcast_arrays() got an unexpected keyword '
|
||||
'argument {!r}'.format(list(kwargs.keys())[0]))
|
||||
args = [np.array(_m, copy=False, subok=subok) for _m in args]
|
||||
|
||||
shape = _broadcast_shape(*args)
|
||||
|
||||
if all(array.shape == shape for array in args):
|
||||
# Common case where nothing needs to be broadcasted.
|
||||
return args
|
||||
|
||||
# TODO: consider making the results of broadcast_arrays readonly to match
|
||||
# broadcast_to. This will require a deprecation cycle.
|
||||
return [_broadcast_to(array, shape, subok=subok, readonly=False)
|
||||
for array in args]
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,378 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
from tempfile import mkdtemp, mkstemp, NamedTemporaryFile
|
||||
from shutil import rmtree
|
||||
|
||||
import numpy.lib._datasource as datasource
|
||||
from numpy.testing import (
|
||||
assert_, assert_equal, assert_raises, assert_warns
|
||||
)
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
import urllib.request as urllib_request
|
||||
from urllib.parse import urlparse
|
||||
from urllib.error import URLError
|
||||
else:
|
||||
import urllib2 as urllib_request
|
||||
from urlparse import urlparse
|
||||
from urllib2 import URLError
|
||||
|
||||
|
||||
def urlopen_stub(url, data=None):
|
||||
'''Stub to replace urlopen for testing.'''
|
||||
if url == valid_httpurl():
|
||||
tmpfile = NamedTemporaryFile(prefix='urltmp_')
|
||||
return tmpfile
|
||||
else:
|
||||
raise URLError('Name or service not known')
|
||||
|
||||
# setup and teardown
|
||||
old_urlopen = None
|
||||
|
||||
|
||||
def setup_module():
|
||||
global old_urlopen
|
||||
|
||||
old_urlopen = urllib_request.urlopen
|
||||
urllib_request.urlopen = urlopen_stub
|
||||
|
||||
|
||||
def teardown_module():
|
||||
urllib_request.urlopen = old_urlopen
|
||||
|
||||
# A valid website for more robust testing
|
||||
http_path = 'http://www.google.com/'
|
||||
http_file = 'index.html'
|
||||
|
||||
http_fakepath = 'http://fake.abc.web/site/'
|
||||
http_fakefile = 'fake.txt'
|
||||
|
||||
malicious_files = ['/etc/shadow', '../../shadow',
|
||||
'..\\system.dat', 'c:\\windows\\system.dat']
|
||||
|
||||
magic_line = b'three is the magic number'
|
||||
|
||||
|
||||
# Utility functions used by many tests
|
||||
def valid_textfile(filedir):
|
||||
# Generate and return a valid temporary file.
|
||||
fd, path = mkstemp(suffix='.txt', prefix='dstmp_', dir=filedir, text=True)
|
||||
os.close(fd)
|
||||
return path
|
||||
|
||||
|
||||
def invalid_textfile(filedir):
|
||||
# Generate and return an invalid filename.
|
||||
fd, path = mkstemp(suffix='.txt', prefix='dstmp_', dir=filedir)
|
||||
os.close(fd)
|
||||
os.remove(path)
|
||||
return path
|
||||
|
||||
|
||||
def valid_httpurl():
|
||||
return http_path+http_file
|
||||
|
||||
|
||||
def invalid_httpurl():
|
||||
return http_fakepath+http_fakefile
|
||||
|
||||
|
||||
def valid_baseurl():
|
||||
return http_path
|
||||
|
||||
|
||||
def invalid_baseurl():
|
||||
return http_fakepath
|
||||
|
||||
|
||||
def valid_httpfile():
|
||||
return http_file
|
||||
|
||||
|
||||
def invalid_httpfile():
|
||||
return http_fakefile
|
||||
|
||||
|
||||
class TestDataSourceOpen(object):
|
||||
def setup(self):
|
||||
self.tmpdir = mkdtemp()
|
||||
self.ds = datasource.DataSource(self.tmpdir)
|
||||
|
||||
def teardown(self):
|
||||
rmtree(self.tmpdir)
|
||||
del self.ds
|
||||
|
||||
def test_ValidHTTP(self):
|
||||
fh = self.ds.open(valid_httpurl())
|
||||
assert_(fh)
|
||||
fh.close()
|
||||
|
||||
def test_InvalidHTTP(self):
|
||||
url = invalid_httpurl()
|
||||
assert_raises(IOError, self.ds.open, url)
|
||||
try:
|
||||
self.ds.open(url)
|
||||
except IOError as e:
|
||||
# Regression test for bug fixed in r4342.
|
||||
assert_(e.errno is None)
|
||||
|
||||
def test_InvalidHTTPCacheURLError(self):
|
||||
assert_raises(URLError, self.ds._cache, invalid_httpurl())
|
||||
|
||||
def test_ValidFile(self):
|
||||
local_file = valid_textfile(self.tmpdir)
|
||||
fh = self.ds.open(local_file)
|
||||
assert_(fh)
|
||||
fh.close()
|
||||
|
||||
def test_InvalidFile(self):
|
||||
invalid_file = invalid_textfile(self.tmpdir)
|
||||
assert_raises(IOError, self.ds.open, invalid_file)
|
||||
|
||||
def test_ValidGzipFile(self):
|
||||
try:
|
||||
import gzip
|
||||
except ImportError:
|
||||
# We don't have the gzip capabilities to test.
|
||||
pytest.skip()
|
||||
# Test datasource's internal file_opener for Gzip files.
|
||||
filepath = os.path.join(self.tmpdir, 'foobar.txt.gz')
|
||||
fp = gzip.open(filepath, 'w')
|
||||
fp.write(magic_line)
|
||||
fp.close()
|
||||
fp = self.ds.open(filepath)
|
||||
result = fp.readline()
|
||||
fp.close()
|
||||
assert_equal(magic_line, result)
|
||||
|
||||
def test_ValidBz2File(self):
|
||||
try:
|
||||
import bz2
|
||||
except ImportError:
|
||||
# We don't have the bz2 capabilities to test.
|
||||
pytest.skip()
|
||||
# Test datasource's internal file_opener for BZip2 files.
|
||||
filepath = os.path.join(self.tmpdir, 'foobar.txt.bz2')
|
||||
fp = bz2.BZ2File(filepath, 'w')
|
||||
fp.write(magic_line)
|
||||
fp.close()
|
||||
fp = self.ds.open(filepath)
|
||||
result = fp.readline()
|
||||
fp.close()
|
||||
assert_equal(magic_line, result)
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[0] >= 3, reason="Python 2 only")
|
||||
def test_Bz2File_text_mode_warning(self):
|
||||
try:
|
||||
import bz2
|
||||
except ImportError:
|
||||
# We don't have the bz2 capabilities to test.
|
||||
pytest.skip()
|
||||
# Test datasource's internal file_opener for BZip2 files.
|
||||
filepath = os.path.join(self.tmpdir, 'foobar.txt.bz2')
|
||||
fp = bz2.BZ2File(filepath, 'w')
|
||||
fp.write(magic_line)
|
||||
fp.close()
|
||||
with assert_warns(RuntimeWarning):
|
||||
fp = self.ds.open(filepath, 'rt')
|
||||
result = fp.readline()
|
||||
fp.close()
|
||||
assert_equal(magic_line, result)
|
||||
|
||||
|
||||
class TestDataSourceExists(object):
|
||||
def setup(self):
|
||||
self.tmpdir = mkdtemp()
|
||||
self.ds = datasource.DataSource(self.tmpdir)
|
||||
|
||||
def teardown(self):
|
||||
rmtree(self.tmpdir)
|
||||
del self.ds
|
||||
|
||||
def test_ValidHTTP(self):
|
||||
assert_(self.ds.exists(valid_httpurl()))
|
||||
|
||||
def test_InvalidHTTP(self):
|
||||
assert_equal(self.ds.exists(invalid_httpurl()), False)
|
||||
|
||||
def test_ValidFile(self):
|
||||
# Test valid file in destpath
|
||||
tmpfile = valid_textfile(self.tmpdir)
|
||||
assert_(self.ds.exists(tmpfile))
|
||||
# Test valid local file not in destpath
|
||||
localdir = mkdtemp()
|
||||
tmpfile = valid_textfile(localdir)
|
||||
assert_(self.ds.exists(tmpfile))
|
||||
rmtree(localdir)
|
||||
|
||||
def test_InvalidFile(self):
|
||||
tmpfile = invalid_textfile(self.tmpdir)
|
||||
assert_equal(self.ds.exists(tmpfile), False)
|
||||
|
||||
|
||||
class TestDataSourceAbspath(object):
|
||||
def setup(self):
|
||||
self.tmpdir = os.path.abspath(mkdtemp())
|
||||
self.ds = datasource.DataSource(self.tmpdir)
|
||||
|
||||
def teardown(self):
|
||||
rmtree(self.tmpdir)
|
||||
del self.ds
|
||||
|
||||
def test_ValidHTTP(self):
|
||||
scheme, netloc, upath, pms, qry, frg = urlparse(valid_httpurl())
|
||||
local_path = os.path.join(self.tmpdir, netloc,
|
||||
upath.strip(os.sep).strip('/'))
|
||||
assert_equal(local_path, self.ds.abspath(valid_httpurl()))
|
||||
|
||||
def test_ValidFile(self):
|
||||
tmpfile = valid_textfile(self.tmpdir)
|
||||
tmpfilename = os.path.split(tmpfile)[-1]
|
||||
# Test with filename only
|
||||
assert_equal(tmpfile, self.ds.abspath(tmpfilename))
|
||||
# Test filename with complete path
|
||||
assert_equal(tmpfile, self.ds.abspath(tmpfile))
|
||||
|
||||
def test_InvalidHTTP(self):
|
||||
scheme, netloc, upath, pms, qry, frg = urlparse(invalid_httpurl())
|
||||
invalidhttp = os.path.join(self.tmpdir, netloc,
|
||||
upath.strip(os.sep).strip('/'))
|
||||
assert_(invalidhttp != self.ds.abspath(valid_httpurl()))
|
||||
|
||||
def test_InvalidFile(self):
|
||||
invalidfile = valid_textfile(self.tmpdir)
|
||||
tmpfile = valid_textfile(self.tmpdir)
|
||||
tmpfilename = os.path.split(tmpfile)[-1]
|
||||
# Test with filename only
|
||||
assert_(invalidfile != self.ds.abspath(tmpfilename))
|
||||
# Test filename with complete path
|
||||
assert_(invalidfile != self.ds.abspath(tmpfile))
|
||||
|
||||
def test_sandboxing(self):
|
||||
tmpfile = valid_textfile(self.tmpdir)
|
||||
tmpfilename = os.path.split(tmpfile)[-1]
|
||||
|
||||
tmp_path = lambda x: os.path.abspath(self.ds.abspath(x))
|
||||
|
||||
assert_(tmp_path(valid_httpurl()).startswith(self.tmpdir))
|
||||
assert_(tmp_path(invalid_httpurl()).startswith(self.tmpdir))
|
||||
assert_(tmp_path(tmpfile).startswith(self.tmpdir))
|
||||
assert_(tmp_path(tmpfilename).startswith(self.tmpdir))
|
||||
for fn in malicious_files:
|
||||
assert_(tmp_path(http_path+fn).startswith(self.tmpdir))
|
||||
assert_(tmp_path(fn).startswith(self.tmpdir))
|
||||
|
||||
def test_windows_os_sep(self):
|
||||
orig_os_sep = os.sep
|
||||
try:
|
||||
os.sep = '\\'
|
||||
self.test_ValidHTTP()
|
||||
self.test_ValidFile()
|
||||
self.test_InvalidHTTP()
|
||||
self.test_InvalidFile()
|
||||
self.test_sandboxing()
|
||||
finally:
|
||||
os.sep = orig_os_sep
|
||||
|
||||
|
||||
class TestRepositoryAbspath(object):
|
||||
def setup(self):
|
||||
self.tmpdir = os.path.abspath(mkdtemp())
|
||||
self.repos = datasource.Repository(valid_baseurl(), self.tmpdir)
|
||||
|
||||
def teardown(self):
|
||||
rmtree(self.tmpdir)
|
||||
del self.repos
|
||||
|
||||
def test_ValidHTTP(self):
|
||||
scheme, netloc, upath, pms, qry, frg = urlparse(valid_httpurl())
|
||||
local_path = os.path.join(self.repos._destpath, netloc,
|
||||
upath.strip(os.sep).strip('/'))
|
||||
filepath = self.repos.abspath(valid_httpfile())
|
||||
assert_equal(local_path, filepath)
|
||||
|
||||
def test_sandboxing(self):
|
||||
tmp_path = lambda x: os.path.abspath(self.repos.abspath(x))
|
||||
assert_(tmp_path(valid_httpfile()).startswith(self.tmpdir))
|
||||
for fn in malicious_files:
|
||||
assert_(tmp_path(http_path+fn).startswith(self.tmpdir))
|
||||
assert_(tmp_path(fn).startswith(self.tmpdir))
|
||||
|
||||
def test_windows_os_sep(self):
|
||||
orig_os_sep = os.sep
|
||||
try:
|
||||
os.sep = '\\'
|
||||
self.test_ValidHTTP()
|
||||
self.test_sandboxing()
|
||||
finally:
|
||||
os.sep = orig_os_sep
|
||||
|
||||
|
||||
class TestRepositoryExists(object):
|
||||
def setup(self):
|
||||
self.tmpdir = mkdtemp()
|
||||
self.repos = datasource.Repository(valid_baseurl(), self.tmpdir)
|
||||
|
||||
def teardown(self):
|
||||
rmtree(self.tmpdir)
|
||||
del self.repos
|
||||
|
||||
def test_ValidFile(self):
|
||||
# Create local temp file
|
||||
tmpfile = valid_textfile(self.tmpdir)
|
||||
assert_(self.repos.exists(tmpfile))
|
||||
|
||||
def test_InvalidFile(self):
|
||||
tmpfile = invalid_textfile(self.tmpdir)
|
||||
assert_equal(self.repos.exists(tmpfile), False)
|
||||
|
||||
def test_RemoveHTTPFile(self):
|
||||
assert_(self.repos.exists(valid_httpurl()))
|
||||
|
||||
def test_CachedHTTPFile(self):
|
||||
localfile = valid_httpurl()
|
||||
# Create a locally cached temp file with an URL based
|
||||
# directory structure. This is similar to what Repository.open
|
||||
# would do.
|
||||
scheme, netloc, upath, pms, qry, frg = urlparse(localfile)
|
||||
local_path = os.path.join(self.repos._destpath, netloc)
|
||||
os.mkdir(local_path, 0o0700)
|
||||
tmpfile = valid_textfile(local_path)
|
||||
assert_(self.repos.exists(tmpfile))
|
||||
|
||||
|
||||
class TestOpenFunc(object):
|
||||
def setup(self):
|
||||
self.tmpdir = mkdtemp()
|
||||
|
||||
def teardown(self):
|
||||
rmtree(self.tmpdir)
|
||||
|
||||
def test_DataSourceOpen(self):
|
||||
local_file = valid_textfile(self.tmpdir)
|
||||
# Test case where destpath is passed in
|
||||
fp = datasource.open(local_file, destpath=self.tmpdir)
|
||||
assert_(fp)
|
||||
fp.close()
|
||||
# Test case where default destpath is used
|
||||
fp = datasource.open(local_file)
|
||||
assert_(fp)
|
||||
fp.close()
|
||||
|
||||
def test_del_attr_handling():
|
||||
# DataSource __del__ can be called
|
||||
# even if __init__ fails when the
|
||||
# Exception object is caught by the
|
||||
# caller as happens in refguide_check
|
||||
# is_deprecated() function
|
||||
|
||||
ds = datasource.DataSource()
|
||||
# simulate failed __init__ by removing key attribute
|
||||
# produced within __init__ and expected by __del__
|
||||
del ds._istmpdest
|
||||
# should not raise an AttributeError if __del__
|
||||
# gracefully handles failed __init__:
|
||||
ds.__del__()
|
||||
@@ -0,0 +1,352 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import time
|
||||
from datetime import date
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import (
|
||||
assert_, assert_equal, assert_allclose, assert_raises,
|
||||
)
|
||||
from numpy.lib._iotools import (
|
||||
LineSplitter, NameValidator, StringConverter,
|
||||
has_nested_fields, easy_dtype, flatten_dtype
|
||||
)
|
||||
from numpy.compat import unicode
|
||||
|
||||
|
||||
class TestLineSplitter(object):
|
||||
"Tests the LineSplitter class."
|
||||
|
||||
def test_no_delimiter(self):
|
||||
"Test LineSplitter w/o delimiter"
|
||||
strg = " 1 2 3 4 5 # test"
|
||||
test = LineSplitter()(strg)
|
||||
assert_equal(test, ['1', '2', '3', '4', '5'])
|
||||
test = LineSplitter('')(strg)
|
||||
assert_equal(test, ['1', '2', '3', '4', '5'])
|
||||
|
||||
def test_space_delimiter(self):
|
||||
"Test space delimiter"
|
||||
strg = " 1 2 3 4 5 # test"
|
||||
test = LineSplitter(' ')(strg)
|
||||
assert_equal(test, ['1', '2', '3', '4', '', '5'])
|
||||
test = LineSplitter(' ')(strg)
|
||||
assert_equal(test, ['1 2 3 4', '5'])
|
||||
|
||||
def test_tab_delimiter(self):
|
||||
"Test tab delimiter"
|
||||
strg = " 1\t 2\t 3\t 4\t 5 6"
|
||||
test = LineSplitter('\t')(strg)
|
||||
assert_equal(test, ['1', '2', '3', '4', '5 6'])
|
||||
strg = " 1 2\t 3 4\t 5 6"
|
||||
test = LineSplitter('\t')(strg)
|
||||
assert_equal(test, ['1 2', '3 4', '5 6'])
|
||||
|
||||
def test_other_delimiter(self):
|
||||
"Test LineSplitter on delimiter"
|
||||
strg = "1,2,3,4,,5"
|
||||
test = LineSplitter(',')(strg)
|
||||
assert_equal(test, ['1', '2', '3', '4', '', '5'])
|
||||
#
|
||||
strg = " 1,2,3,4,,5 # test"
|
||||
test = LineSplitter(',')(strg)
|
||||
assert_equal(test, ['1', '2', '3', '4', '', '5'])
|
||||
|
||||
# gh-11028 bytes comment/delimiters should get encoded
|
||||
strg = b" 1,2,3,4,,5 % test"
|
||||
test = LineSplitter(delimiter=b',', comments=b'%')(strg)
|
||||
assert_equal(test, ['1', '2', '3', '4', '', '5'])
|
||||
|
||||
def test_constant_fixed_width(self):
|
||||
"Test LineSplitter w/ fixed-width fields"
|
||||
strg = " 1 2 3 4 5 # test"
|
||||
test = LineSplitter(3)(strg)
|
||||
assert_equal(test, ['1', '2', '3', '4', '', '5', ''])
|
||||
#
|
||||
strg = " 1 3 4 5 6# test"
|
||||
test = LineSplitter(20)(strg)
|
||||
assert_equal(test, ['1 3 4 5 6'])
|
||||
#
|
||||
strg = " 1 3 4 5 6# test"
|
||||
test = LineSplitter(30)(strg)
|
||||
assert_equal(test, ['1 3 4 5 6'])
|
||||
|
||||
def test_variable_fixed_width(self):
|
||||
strg = " 1 3 4 5 6# test"
|
||||
test = LineSplitter((3, 6, 6, 3))(strg)
|
||||
assert_equal(test, ['1', '3', '4 5', '6'])
|
||||
#
|
||||
strg = " 1 3 4 5 6# test"
|
||||
test = LineSplitter((6, 6, 9))(strg)
|
||||
assert_equal(test, ['1', '3 4', '5 6'])
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestNameValidator(object):
|
||||
|
||||
def test_case_sensitivity(self):
|
||||
"Test case sensitivity"
|
||||
names = ['A', 'a', 'b', 'c']
|
||||
test = NameValidator().validate(names)
|
||||
assert_equal(test, ['A', 'a', 'b', 'c'])
|
||||
test = NameValidator(case_sensitive=False).validate(names)
|
||||
assert_equal(test, ['A', 'A_1', 'B', 'C'])
|
||||
test = NameValidator(case_sensitive='upper').validate(names)
|
||||
assert_equal(test, ['A', 'A_1', 'B', 'C'])
|
||||
test = NameValidator(case_sensitive='lower').validate(names)
|
||||
assert_equal(test, ['a', 'a_1', 'b', 'c'])
|
||||
|
||||
# check exceptions
|
||||
assert_raises(ValueError, NameValidator, case_sensitive='foobar')
|
||||
|
||||
def test_excludelist(self):
|
||||
"Test excludelist"
|
||||
names = ['dates', 'data', 'Other Data', 'mask']
|
||||
validator = NameValidator(excludelist=['dates', 'data', 'mask'])
|
||||
test = validator.validate(names)
|
||||
assert_equal(test, ['dates_', 'data_', 'Other_Data', 'mask_'])
|
||||
|
||||
def test_missing_names(self):
|
||||
"Test validate missing names"
|
||||
namelist = ('a', 'b', 'c')
|
||||
validator = NameValidator()
|
||||
assert_equal(validator(namelist), ['a', 'b', 'c'])
|
||||
namelist = ('', 'b', 'c')
|
||||
assert_equal(validator(namelist), ['f0', 'b', 'c'])
|
||||
namelist = ('a', 'b', '')
|
||||
assert_equal(validator(namelist), ['a', 'b', 'f0'])
|
||||
namelist = ('', 'f0', '')
|
||||
assert_equal(validator(namelist), ['f1', 'f0', 'f2'])
|
||||
|
||||
def test_validate_nb_names(self):
|
||||
"Test validate nb names"
|
||||
namelist = ('a', 'b', 'c')
|
||||
validator = NameValidator()
|
||||
assert_equal(validator(namelist, nbfields=1), ('a',))
|
||||
assert_equal(validator(namelist, nbfields=5, defaultfmt="g%i"),
|
||||
['a', 'b', 'c', 'g0', 'g1'])
|
||||
|
||||
def test_validate_wo_names(self):
|
||||
"Test validate no names"
|
||||
namelist = None
|
||||
validator = NameValidator()
|
||||
assert_(validator(namelist) is None)
|
||||
assert_equal(validator(namelist, nbfields=3), ['f0', 'f1', 'f2'])
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _bytes_to_date(s):
|
||||
return date(*time.strptime(s, "%Y-%m-%d")[:3])
|
||||
|
||||
|
||||
class TestStringConverter(object):
|
||||
"Test StringConverter"
|
||||
|
||||
def test_creation(self):
|
||||
"Test creation of a StringConverter"
|
||||
converter = StringConverter(int, -99999)
|
||||
assert_equal(converter._status, 1)
|
||||
assert_equal(converter.default, -99999)
|
||||
|
||||
def test_upgrade(self):
|
||||
"Tests the upgrade method."
|
||||
|
||||
converter = StringConverter()
|
||||
assert_equal(converter._status, 0)
|
||||
|
||||
# test int
|
||||
assert_equal(converter.upgrade('0'), 0)
|
||||
assert_equal(converter._status, 1)
|
||||
|
||||
# On systems where long defaults to 32-bit, the statuses will be
|
||||
# offset by one, so we check for this here.
|
||||
import numpy.core.numeric as nx
|
||||
status_offset = int(nx.dtype(nx.int_).itemsize < nx.dtype(nx.int64).itemsize)
|
||||
|
||||
# test int > 2**32
|
||||
assert_equal(converter.upgrade('17179869184'), 17179869184)
|
||||
assert_equal(converter._status, 1 + status_offset)
|
||||
|
||||
# test float
|
||||
assert_allclose(converter.upgrade('0.'), 0.0)
|
||||
assert_equal(converter._status, 2 + status_offset)
|
||||
|
||||
# test complex
|
||||
assert_equal(converter.upgrade('0j'), complex('0j'))
|
||||
assert_equal(converter._status, 3 + status_offset)
|
||||
|
||||
# test str
|
||||
# note that the longdouble type has been skipped, so the
|
||||
# _status increases by 2. Everything should succeed with
|
||||
# unicode conversion (5).
|
||||
for s in ['a', u'a', b'a']:
|
||||
res = converter.upgrade(s)
|
||||
assert_(type(res) is unicode)
|
||||
assert_equal(res, u'a')
|
||||
assert_equal(converter._status, 5 + status_offset)
|
||||
|
||||
def test_missing(self):
|
||||
"Tests the use of missing values."
|
||||
converter = StringConverter(missing_values=('missing',
|
||||
'missed'))
|
||||
converter.upgrade('0')
|
||||
assert_equal(converter('0'), 0)
|
||||
assert_equal(converter(''), converter.default)
|
||||
assert_equal(converter('missing'), converter.default)
|
||||
assert_equal(converter('missed'), converter.default)
|
||||
try:
|
||||
converter('miss')
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def test_upgrademapper(self):
|
||||
"Tests updatemapper"
|
||||
dateparser = _bytes_to_date
|
||||
StringConverter.upgrade_mapper(dateparser, date(2000, 1, 1))
|
||||
convert = StringConverter(dateparser, date(2000, 1, 1))
|
||||
test = convert('2001-01-01')
|
||||
assert_equal(test, date(2001, 1, 1))
|
||||
test = convert('2009-01-01')
|
||||
assert_equal(test, date(2009, 1, 1))
|
||||
test = convert('')
|
||||
assert_equal(test, date(2000, 1, 1))
|
||||
|
||||
def test_string_to_object(self):
|
||||
"Make sure that string-to-object functions are properly recognized"
|
||||
old_mapper = StringConverter._mapper[:] # copy of list
|
||||
conv = StringConverter(_bytes_to_date)
|
||||
assert_equal(conv._mapper, old_mapper)
|
||||
assert_(hasattr(conv, 'default'))
|
||||
|
||||
def test_keep_default(self):
|
||||
"Make sure we don't lose an explicit default"
|
||||
converter = StringConverter(None, missing_values='',
|
||||
default=-999)
|
||||
converter.upgrade('3.14159265')
|
||||
assert_equal(converter.default, -999)
|
||||
assert_equal(converter.type, np.dtype(float))
|
||||
#
|
||||
converter = StringConverter(
|
||||
None, missing_values='', default=0)
|
||||
converter.upgrade('3.14159265')
|
||||
assert_equal(converter.default, 0)
|
||||
assert_equal(converter.type, np.dtype(float))
|
||||
|
||||
def test_keep_default_zero(self):
|
||||
"Check that we don't lose a default of 0"
|
||||
converter = StringConverter(int, default=0,
|
||||
missing_values="N/A")
|
||||
assert_equal(converter.default, 0)
|
||||
|
||||
def test_keep_missing_values(self):
|
||||
"Check that we're not losing missing values"
|
||||
converter = StringConverter(int, default=0,
|
||||
missing_values="N/A")
|
||||
assert_equal(
|
||||
converter.missing_values, {'', 'N/A'})
|
||||
|
||||
def test_int64_dtype(self):
|
||||
"Check that int64 integer types can be specified"
|
||||
converter = StringConverter(np.int64, default=0)
|
||||
val = "-9223372036854775807"
|
||||
assert_(converter(val) == -9223372036854775807)
|
||||
val = "9223372036854775807"
|
||||
assert_(converter(val) == 9223372036854775807)
|
||||
|
||||
def test_uint64_dtype(self):
|
||||
"Check that uint64 integer types can be specified"
|
||||
converter = StringConverter(np.uint64, default=0)
|
||||
val = "9223372043271415339"
|
||||
assert_(converter(val) == 9223372043271415339)
|
||||
|
||||
|
||||
class TestMiscFunctions(object):
|
||||
|
||||
def test_has_nested_dtype(self):
|
||||
"Test has_nested_dtype"
|
||||
ndtype = np.dtype(float)
|
||||
assert_equal(has_nested_fields(ndtype), False)
|
||||
ndtype = np.dtype([('A', '|S3'), ('B', float)])
|
||||
assert_equal(has_nested_fields(ndtype), False)
|
||||
ndtype = np.dtype([('A', int), ('B', [('BA', float), ('BB', '|S1')])])
|
||||
assert_equal(has_nested_fields(ndtype), True)
|
||||
|
||||
def test_easy_dtype(self):
|
||||
"Test ndtype on dtypes"
|
||||
# Simple case
|
||||
ndtype = float
|
||||
assert_equal(easy_dtype(ndtype), np.dtype(float))
|
||||
# As string w/o names
|
||||
ndtype = "i4, f8"
|
||||
assert_equal(easy_dtype(ndtype),
|
||||
np.dtype([('f0', "i4"), ('f1', "f8")]))
|
||||
# As string w/o names but different default format
|
||||
assert_equal(easy_dtype(ndtype, defaultfmt="field_%03i"),
|
||||
np.dtype([('field_000', "i4"), ('field_001', "f8")]))
|
||||
# As string w/ names
|
||||
ndtype = "i4, f8"
|
||||
assert_equal(easy_dtype(ndtype, names="a, b"),
|
||||
np.dtype([('a', "i4"), ('b', "f8")]))
|
||||
# As string w/ names (too many)
|
||||
ndtype = "i4, f8"
|
||||
assert_equal(easy_dtype(ndtype, names="a, b, c"),
|
||||
np.dtype([('a', "i4"), ('b', "f8")]))
|
||||
# As string w/ names (not enough)
|
||||
ndtype = "i4, f8"
|
||||
assert_equal(easy_dtype(ndtype, names=", b"),
|
||||
np.dtype([('f0', "i4"), ('b', "f8")]))
|
||||
# ... (with different default format)
|
||||
assert_equal(easy_dtype(ndtype, names="a", defaultfmt="f%02i"),
|
||||
np.dtype([('a', "i4"), ('f00', "f8")]))
|
||||
# As list of tuples w/o names
|
||||
ndtype = [('A', int), ('B', float)]
|
||||
assert_equal(easy_dtype(ndtype), np.dtype([('A', int), ('B', float)]))
|
||||
# As list of tuples w/ names
|
||||
assert_equal(easy_dtype(ndtype, names="a,b"),
|
||||
np.dtype([('a', int), ('b', float)]))
|
||||
# As list of tuples w/ not enough names
|
||||
assert_equal(easy_dtype(ndtype, names="a"),
|
||||
np.dtype([('a', int), ('f0', float)]))
|
||||
# As list of tuples w/ too many names
|
||||
assert_equal(easy_dtype(ndtype, names="a,b,c"),
|
||||
np.dtype([('a', int), ('b', float)]))
|
||||
# As list of types w/o names
|
||||
ndtype = (int, float, float)
|
||||
assert_equal(easy_dtype(ndtype),
|
||||
np.dtype([('f0', int), ('f1', float), ('f2', float)]))
|
||||
# As list of types w names
|
||||
ndtype = (int, float, float)
|
||||
assert_equal(easy_dtype(ndtype, names="a, b, c"),
|
||||
np.dtype([('a', int), ('b', float), ('c', float)]))
|
||||
# As simple dtype w/ names
|
||||
ndtype = np.dtype(float)
|
||||
assert_equal(easy_dtype(ndtype, names="a, b, c"),
|
||||
np.dtype([(_, float) for _ in ('a', 'b', 'c')]))
|
||||
# As simple dtype w/o names (but multiple fields)
|
||||
ndtype = np.dtype(float)
|
||||
assert_equal(
|
||||
easy_dtype(ndtype, names=['', '', ''], defaultfmt="f%02i"),
|
||||
np.dtype([(_, float) for _ in ('f00', 'f01', 'f02')]))
|
||||
|
||||
def test_flatten_dtype(self):
|
||||
"Testing flatten_dtype"
|
||||
# Standard dtype
|
||||
dt = np.dtype([("a", "f8"), ("b", "f8")])
|
||||
dt_flat = flatten_dtype(dt)
|
||||
assert_equal(dt_flat, [float, float])
|
||||
# Recursive dtype
|
||||
dt = np.dtype([("a", [("aa", '|S1'), ("ab", '|S2')]), ("b", int)])
|
||||
dt_flat = flatten_dtype(dt)
|
||||
assert_equal(dt_flat, [np.dtype('|S1'), np.dtype('|S2'), int])
|
||||
# dtype with shaped fields
|
||||
dt = np.dtype([("a", (float, 2)), ("b", (int, 3))])
|
||||
dt_flat = flatten_dtype(dt)
|
||||
assert_equal(dt_flat, [float, int])
|
||||
dt_flat = flatten_dtype(dt, True)
|
||||
assert_equal(dt_flat, [float] * 2 + [int] * 3)
|
||||
# dtype w/ titles
|
||||
dt = np.dtype([(("a", "A"), "f8"), (("b", "B"), "f8")])
|
||||
dt_flat = flatten_dtype(dt)
|
||||
assert_equal(dt_flat, [float, float])
|
||||
@@ -0,0 +1,66 @@
|
||||
"""Tests for the NumpyVersion class.
|
||||
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
from numpy.testing import assert_, assert_raises
|
||||
from numpy.lib import NumpyVersion
|
||||
|
||||
|
||||
def test_main_versions():
|
||||
assert_(NumpyVersion('1.8.0') == '1.8.0')
|
||||
for ver in ['1.9.0', '2.0.0', '1.8.1']:
|
||||
assert_(NumpyVersion('1.8.0') < ver)
|
||||
|
||||
for ver in ['1.7.0', '1.7.1', '0.9.9']:
|
||||
assert_(NumpyVersion('1.8.0') > ver)
|
||||
|
||||
|
||||
def test_version_1_point_10():
|
||||
# regression test for gh-2998.
|
||||
assert_(NumpyVersion('1.9.0') < '1.10.0')
|
||||
assert_(NumpyVersion('1.11.0') < '1.11.1')
|
||||
assert_(NumpyVersion('1.11.0') == '1.11.0')
|
||||
assert_(NumpyVersion('1.99.11') < '1.99.12')
|
||||
|
||||
|
||||
def test_alpha_beta_rc():
|
||||
assert_(NumpyVersion('1.8.0rc1') == '1.8.0rc1')
|
||||
for ver in ['1.8.0', '1.8.0rc2']:
|
||||
assert_(NumpyVersion('1.8.0rc1') < ver)
|
||||
|
||||
for ver in ['1.8.0a2', '1.8.0b3', '1.7.2rc4']:
|
||||
assert_(NumpyVersion('1.8.0rc1') > ver)
|
||||
|
||||
assert_(NumpyVersion('1.8.0b1') > '1.8.0a2')
|
||||
|
||||
|
||||
def test_dev_version():
|
||||
assert_(NumpyVersion('1.9.0.dev-Unknown') < '1.9.0')
|
||||
for ver in ['1.9.0', '1.9.0a1', '1.9.0b2', '1.9.0b2.dev-ffffffff']:
|
||||
assert_(NumpyVersion('1.9.0.dev-f16acvda') < ver)
|
||||
|
||||
assert_(NumpyVersion('1.9.0.dev-f16acvda') == '1.9.0.dev-11111111')
|
||||
|
||||
|
||||
def test_dev_a_b_rc_mixed():
|
||||
assert_(NumpyVersion('1.9.0a2.dev-f16acvda') == '1.9.0a2.dev-11111111')
|
||||
assert_(NumpyVersion('1.9.0a2.dev-6acvda54') < '1.9.0a2')
|
||||
|
||||
|
||||
def test_dev0_version():
|
||||
assert_(NumpyVersion('1.9.0.dev0+Unknown') < '1.9.0')
|
||||
for ver in ['1.9.0', '1.9.0a1', '1.9.0b2', '1.9.0b2.dev0+ffffffff']:
|
||||
assert_(NumpyVersion('1.9.0.dev0+f16acvda') < ver)
|
||||
|
||||
assert_(NumpyVersion('1.9.0.dev0+f16acvda') == '1.9.0.dev0+11111111')
|
||||
|
||||
|
||||
def test_dev0_a_b_rc_mixed():
|
||||
assert_(NumpyVersion('1.9.0a2.dev0+f16acvda') == '1.9.0a2.dev0+11111111')
|
||||
assert_(NumpyVersion('1.9.0a2.dev0+6acvda54') < '1.9.0a2')
|
||||
|
||||
|
||||
def test_raises():
|
||||
for ver in ['1.9', '1,9.0', '1.7.x']:
|
||||
assert_raises(ValueError, NumpyVersion, ver)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,623 @@
|
||||
"""Test functions for 1D array set operations.
|
||||
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import numpy as np
|
||||
|
||||
from numpy.testing import (assert_array_equal, assert_equal,
|
||||
assert_raises, assert_raises_regex)
|
||||
from numpy.lib.arraysetops import (
|
||||
ediff1d, intersect1d, setxor1d, union1d, setdiff1d, unique, in1d, isin
|
||||
)
|
||||
import pytest
|
||||
|
||||
|
||||
|
||||
class TestSetOps(object):
|
||||
|
||||
def test_intersect1d(self):
|
||||
# unique inputs
|
||||
a = np.array([5, 7, 1, 2])
|
||||
b = np.array([2, 4, 3, 1, 5])
|
||||
|
||||
ec = np.array([1, 2, 5])
|
||||
c = intersect1d(a, b, assume_unique=True)
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
# non-unique inputs
|
||||
a = np.array([5, 5, 7, 1, 2])
|
||||
b = np.array([2, 1, 4, 3, 3, 1, 5])
|
||||
|
||||
ed = np.array([1, 2, 5])
|
||||
c = intersect1d(a, b)
|
||||
assert_array_equal(c, ed)
|
||||
assert_array_equal([], intersect1d([], []))
|
||||
|
||||
def test_intersect1d_array_like(self):
|
||||
# See gh-11772
|
||||
class Test(object):
|
||||
def __array__(self):
|
||||
return np.arange(3)
|
||||
|
||||
a = Test()
|
||||
res = intersect1d(a, a)
|
||||
assert_array_equal(res, a)
|
||||
res = intersect1d([1, 2, 3], [1, 2, 3])
|
||||
assert_array_equal(res, [1, 2, 3])
|
||||
|
||||
def test_intersect1d_indices(self):
|
||||
# unique inputs
|
||||
a = np.array([1, 2, 3, 4])
|
||||
b = np.array([2, 1, 4, 6])
|
||||
c, i1, i2 = intersect1d(a, b, assume_unique=True, return_indices=True)
|
||||
ee = np.array([1, 2, 4])
|
||||
assert_array_equal(c, ee)
|
||||
assert_array_equal(a[i1], ee)
|
||||
assert_array_equal(b[i2], ee)
|
||||
|
||||
# non-unique inputs
|
||||
a = np.array([1, 2, 2, 3, 4, 3, 2])
|
||||
b = np.array([1, 8, 4, 2, 2, 3, 2, 3])
|
||||
c, i1, i2 = intersect1d(a, b, return_indices=True)
|
||||
ef = np.array([1, 2, 3, 4])
|
||||
assert_array_equal(c, ef)
|
||||
assert_array_equal(a[i1], ef)
|
||||
assert_array_equal(b[i2], ef)
|
||||
|
||||
# non1d, unique inputs
|
||||
a = np.array([[2, 4, 5, 6], [7, 8, 1, 15]])
|
||||
b = np.array([[3, 2, 7, 6], [10, 12, 8, 9]])
|
||||
c, i1, i2 = intersect1d(a, b, assume_unique=True, return_indices=True)
|
||||
ui1 = np.unravel_index(i1, a.shape)
|
||||
ui2 = np.unravel_index(i2, b.shape)
|
||||
ea = np.array([2, 6, 7, 8])
|
||||
assert_array_equal(ea, a[ui1])
|
||||
assert_array_equal(ea, b[ui2])
|
||||
|
||||
# non1d, not assumed to be uniqueinputs
|
||||
a = np.array([[2, 4, 5, 6, 6], [4, 7, 8, 7, 2]])
|
||||
b = np.array([[3, 2, 7, 7], [10, 12, 8, 7]])
|
||||
c, i1, i2 = intersect1d(a, b, return_indices=True)
|
||||
ui1 = np.unravel_index(i1, a.shape)
|
||||
ui2 = np.unravel_index(i2, b.shape)
|
||||
ea = np.array([2, 7, 8])
|
||||
assert_array_equal(ea, a[ui1])
|
||||
assert_array_equal(ea, b[ui2])
|
||||
|
||||
def test_setxor1d(self):
|
||||
a = np.array([5, 7, 1, 2])
|
||||
b = np.array([2, 4, 3, 1, 5])
|
||||
|
||||
ec = np.array([3, 4, 7])
|
||||
c = setxor1d(a, b)
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
a = np.array([1, 2, 3])
|
||||
b = np.array([6, 5, 4])
|
||||
|
||||
ec = np.array([1, 2, 3, 4, 5, 6])
|
||||
c = setxor1d(a, b)
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
a = np.array([1, 8, 2, 3])
|
||||
b = np.array([6, 5, 4, 8])
|
||||
|
||||
ec = np.array([1, 2, 3, 4, 5, 6])
|
||||
c = setxor1d(a, b)
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
assert_array_equal([], setxor1d([], []))
|
||||
|
||||
def test_ediff1d(self):
|
||||
zero_elem = np.array([])
|
||||
one_elem = np.array([1])
|
||||
two_elem = np.array([1, 2])
|
||||
|
||||
assert_array_equal([], ediff1d(zero_elem))
|
||||
assert_array_equal([0], ediff1d(zero_elem, to_begin=0))
|
||||
assert_array_equal([0], ediff1d(zero_elem, to_end=0))
|
||||
assert_array_equal([-1, 0], ediff1d(zero_elem, to_begin=-1, to_end=0))
|
||||
assert_array_equal([], ediff1d(one_elem))
|
||||
assert_array_equal([1], ediff1d(two_elem))
|
||||
assert_array_equal([7,1,9], ediff1d(two_elem, to_begin=7, to_end=9))
|
||||
assert_array_equal([5,6,1,7,8], ediff1d(two_elem, to_begin=[5,6], to_end=[7,8]))
|
||||
assert_array_equal([1,9], ediff1d(two_elem, to_end=9))
|
||||
assert_array_equal([1,7,8], ediff1d(two_elem, to_end=[7,8]))
|
||||
assert_array_equal([7,1], ediff1d(two_elem, to_begin=7))
|
||||
assert_array_equal([5,6,1], ediff1d(two_elem, to_begin=[5,6]))
|
||||
|
||||
@pytest.mark.parametrize("ary, prepend, append", [
|
||||
# should fail because trying to cast
|
||||
# np.nan standard floating point value
|
||||
# into an integer array:
|
||||
(np.array([1, 2, 3], dtype=np.int64),
|
||||
None,
|
||||
np.nan),
|
||||
# should fail because attempting
|
||||
# to downcast to smaller int type:
|
||||
(np.array([1, 2, 3], dtype=np.int32),
|
||||
np.array([5, 7, 2], dtype=np.int64),
|
||||
None),
|
||||
# should fail because attempting to cast
|
||||
# two special floating point values
|
||||
# to integers (on both sides of ary):
|
||||
(np.array([1., 3., 9.], dtype=np.int8),
|
||||
np.nan,
|
||||
np.nan),
|
||||
])
|
||||
def test_ediff1d_forbidden_type_casts(self, ary, prepend, append):
|
||||
# verify resolution of gh-11490
|
||||
|
||||
# specifically, raise an appropriate
|
||||
# Exception when attempting to append or
|
||||
# prepend with an incompatible type
|
||||
msg = 'must be compatible'
|
||||
with assert_raises_regex(TypeError, msg):
|
||||
ediff1d(ary=ary,
|
||||
to_end=append,
|
||||
to_begin=prepend)
|
||||
|
||||
@pytest.mark.parametrize("ary,"
|
||||
"prepend,"
|
||||
"append,"
|
||||
"expected", [
|
||||
(np.array([1, 2, 3], dtype=np.int16),
|
||||
0,
|
||||
None,
|
||||
np.array([0, 1, 1], dtype=np.int16)),
|
||||
(np.array([1, 2, 3], dtype=np.int32),
|
||||
0,
|
||||
0,
|
||||
np.array([0, 1, 1, 0], dtype=np.int32)),
|
||||
(np.array([1, 2, 3], dtype=np.int64),
|
||||
3,
|
||||
-9,
|
||||
np.array([3, 1, 1, -9], dtype=np.int64)),
|
||||
])
|
||||
def test_ediff1d_scalar_handling(self,
|
||||
ary,
|
||||
prepend,
|
||||
append,
|
||||
expected):
|
||||
# maintain backwards-compatibility
|
||||
# of scalar prepend / append behavior
|
||||
# in ediff1d following fix for gh-11490
|
||||
actual = np.ediff1d(ary=ary,
|
||||
to_end=append,
|
||||
to_begin=prepend)
|
||||
assert_equal(actual, expected)
|
||||
|
||||
|
||||
def test_isin(self):
|
||||
# the tests for in1d cover most of isin's behavior
|
||||
# if in1d is removed, would need to change those tests to test
|
||||
# isin instead.
|
||||
def _isin_slow(a, b):
|
||||
b = np.asarray(b).flatten().tolist()
|
||||
return a in b
|
||||
isin_slow = np.vectorize(_isin_slow, otypes=[bool], excluded={1})
|
||||
def assert_isin_equal(a, b):
|
||||
x = isin(a, b)
|
||||
y = isin_slow(a, b)
|
||||
assert_array_equal(x, y)
|
||||
|
||||
#multidimensional arrays in both arguments
|
||||
a = np.arange(24).reshape([2, 3, 4])
|
||||
b = np.array([[10, 20, 30], [0, 1, 3], [11, 22, 33]])
|
||||
assert_isin_equal(a, b)
|
||||
|
||||
#array-likes as both arguments
|
||||
c = [(9, 8), (7, 6)]
|
||||
d = (9, 7)
|
||||
assert_isin_equal(c, d)
|
||||
|
||||
#zero-d array:
|
||||
f = np.array(3)
|
||||
assert_isin_equal(f, b)
|
||||
assert_isin_equal(a, f)
|
||||
assert_isin_equal(f, f)
|
||||
|
||||
#scalar:
|
||||
assert_isin_equal(5, b)
|
||||
assert_isin_equal(a, 6)
|
||||
assert_isin_equal(5, 6)
|
||||
|
||||
#empty array-like:
|
||||
x = []
|
||||
assert_isin_equal(x, b)
|
||||
assert_isin_equal(a, x)
|
||||
assert_isin_equal(x, x)
|
||||
|
||||
def test_in1d(self):
|
||||
# we use two different sizes for the b array here to test the
|
||||
# two different paths in in1d().
|
||||
for mult in (1, 10):
|
||||
# One check without np.array to make sure lists are handled correct
|
||||
a = [5, 7, 1, 2]
|
||||
b = [2, 4, 3, 1, 5] * mult
|
||||
ec = np.array([True, False, True, True])
|
||||
c = in1d(a, b, assume_unique=True)
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
a[0] = 8
|
||||
ec = np.array([False, False, True, True])
|
||||
c = in1d(a, b, assume_unique=True)
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
a[0], a[3] = 4, 8
|
||||
ec = np.array([True, False, True, False])
|
||||
c = in1d(a, b, assume_unique=True)
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
a = np.array([5, 4, 5, 3, 4, 4, 3, 4, 3, 5, 2, 1, 5, 5])
|
||||
b = [2, 3, 4] * mult
|
||||
ec = [False, True, False, True, True, True, True, True, True,
|
||||
False, True, False, False, False]
|
||||
c = in1d(a, b)
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
b = b + [5, 5, 4] * mult
|
||||
ec = [True, True, True, True, True, True, True, True, True, True,
|
||||
True, False, True, True]
|
||||
c = in1d(a, b)
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
a = np.array([5, 7, 1, 2])
|
||||
b = np.array([2, 4, 3, 1, 5] * mult)
|
||||
ec = np.array([True, False, True, True])
|
||||
c = in1d(a, b)
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
a = np.array([5, 7, 1, 1, 2])
|
||||
b = np.array([2, 4, 3, 3, 1, 5] * mult)
|
||||
ec = np.array([True, False, True, True, True])
|
||||
c = in1d(a, b)
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
a = np.array([5, 5])
|
||||
b = np.array([2, 2] * mult)
|
||||
ec = np.array([False, False])
|
||||
c = in1d(a, b)
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
a = np.array([5])
|
||||
b = np.array([2])
|
||||
ec = np.array([False])
|
||||
c = in1d(a, b)
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
assert_array_equal(in1d([], []), [])
|
||||
|
||||
def test_in1d_char_array(self):
|
||||
a = np.array(['a', 'b', 'c', 'd', 'e', 'c', 'e', 'b'])
|
||||
b = np.array(['a', 'c'])
|
||||
|
||||
ec = np.array([True, False, True, False, False, True, False, False])
|
||||
c = in1d(a, b)
|
||||
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
def test_in1d_invert(self):
|
||||
"Test in1d's invert parameter"
|
||||
# We use two different sizes for the b array here to test the
|
||||
# two different paths in in1d().
|
||||
for mult in (1, 10):
|
||||
a = np.array([5, 4, 5, 3, 4, 4, 3, 4, 3, 5, 2, 1, 5, 5])
|
||||
b = [2, 3, 4] * mult
|
||||
assert_array_equal(np.invert(in1d(a, b)), in1d(a, b, invert=True))
|
||||
|
||||
def test_in1d_ravel(self):
|
||||
# Test that in1d ravels its input arrays. This is not documented
|
||||
# behavior however. The test is to ensure consistentency.
|
||||
a = np.arange(6).reshape(2, 3)
|
||||
b = np.arange(3, 9).reshape(3, 2)
|
||||
long_b = np.arange(3, 63).reshape(30, 2)
|
||||
ec = np.array([False, False, False, True, True, True])
|
||||
|
||||
assert_array_equal(in1d(a, b, assume_unique=True), ec)
|
||||
assert_array_equal(in1d(a, b, assume_unique=False), ec)
|
||||
assert_array_equal(in1d(a, long_b, assume_unique=True), ec)
|
||||
assert_array_equal(in1d(a, long_b, assume_unique=False), ec)
|
||||
|
||||
def test_in1d_first_array_is_object(self):
|
||||
ar1 = [None]
|
||||
ar2 = np.array([1]*10)
|
||||
expected = np.array([False])
|
||||
result = np.in1d(ar1, ar2)
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
def test_in1d_second_array_is_object(self):
|
||||
ar1 = 1
|
||||
ar2 = np.array([None]*10)
|
||||
expected = np.array([False])
|
||||
result = np.in1d(ar1, ar2)
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
def test_in1d_both_arrays_are_object(self):
|
||||
ar1 = [None]
|
||||
ar2 = np.array([None]*10)
|
||||
expected = np.array([True])
|
||||
result = np.in1d(ar1, ar2)
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
def test_in1d_both_arrays_have_structured_dtype(self):
|
||||
# Test arrays of a structured data type containing an integer field
|
||||
# and a field of dtype `object` allowing for arbitrary Python objects
|
||||
dt = np.dtype([('field1', int), ('field2', object)])
|
||||
ar1 = np.array([(1, None)], dtype=dt)
|
||||
ar2 = np.array([(1, None)]*10, dtype=dt)
|
||||
expected = np.array([True])
|
||||
result = np.in1d(ar1, ar2)
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
def test_union1d(self):
|
||||
a = np.array([5, 4, 7, 1, 2])
|
||||
b = np.array([2, 4, 3, 3, 2, 1, 5])
|
||||
|
||||
ec = np.array([1, 2, 3, 4, 5, 7])
|
||||
c = union1d(a, b)
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
# Tests gh-10340, arguments to union1d should be
|
||||
# flattened if they are not already 1D
|
||||
x = np.array([[0, 1, 2], [3, 4, 5]])
|
||||
y = np.array([0, 1, 2, 3, 4])
|
||||
ez = np.array([0, 1, 2, 3, 4, 5])
|
||||
z = union1d(x, y)
|
||||
assert_array_equal(z, ez)
|
||||
|
||||
assert_array_equal([], union1d([], []))
|
||||
|
||||
def test_setdiff1d(self):
|
||||
a = np.array([6, 5, 4, 7, 1, 2, 7, 4])
|
||||
b = np.array([2, 4, 3, 3, 2, 1, 5])
|
||||
|
||||
ec = np.array([6, 7])
|
||||
c = setdiff1d(a, b)
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
a = np.arange(21)
|
||||
b = np.arange(19)
|
||||
ec = np.array([19, 20])
|
||||
c = setdiff1d(a, b)
|
||||
assert_array_equal(c, ec)
|
||||
|
||||
assert_array_equal([], setdiff1d([], []))
|
||||
a = np.array((), np.uint32)
|
||||
assert_equal(setdiff1d(a, []).dtype, np.uint32)
|
||||
|
||||
def test_setdiff1d_unique(self):
|
||||
a = np.array([3, 2, 1])
|
||||
b = np.array([7, 5, 2])
|
||||
expected = np.array([3, 1])
|
||||
actual = setdiff1d(a, b, assume_unique=True)
|
||||
assert_equal(actual, expected)
|
||||
|
||||
def test_setdiff1d_char_array(self):
|
||||
a = np.array(['a', 'b', 'c'])
|
||||
b = np.array(['a', 'b', 's'])
|
||||
assert_array_equal(setdiff1d(a, b), np.array(['c']))
|
||||
|
||||
def test_manyways(self):
|
||||
a = np.array([5, 7, 1, 2, 8])
|
||||
b = np.array([9, 8, 2, 4, 3, 1, 5])
|
||||
|
||||
c1 = setxor1d(a, b)
|
||||
aux1 = intersect1d(a, b)
|
||||
aux2 = union1d(a, b)
|
||||
c2 = setdiff1d(aux2, aux1)
|
||||
assert_array_equal(c1, c2)
|
||||
|
||||
|
||||
class TestUnique(object):
|
||||
|
||||
def test_unique_1d(self):
|
||||
|
||||
def check_all(a, b, i1, i2, c, dt):
|
||||
base_msg = 'check {0} failed for type {1}'
|
||||
|
||||
msg = base_msg.format('values', dt)
|
||||
v = unique(a)
|
||||
assert_array_equal(v, b, msg)
|
||||
|
||||
msg = base_msg.format('return_index', dt)
|
||||
v, j = unique(a, 1, 0, 0)
|
||||
assert_array_equal(v, b, msg)
|
||||
assert_array_equal(j, i1, msg)
|
||||
|
||||
msg = base_msg.format('return_inverse', dt)
|
||||
v, j = unique(a, 0, 1, 0)
|
||||
assert_array_equal(v, b, msg)
|
||||
assert_array_equal(j, i2, msg)
|
||||
|
||||
msg = base_msg.format('return_counts', dt)
|
||||
v, j = unique(a, 0, 0, 1)
|
||||
assert_array_equal(v, b, msg)
|
||||
assert_array_equal(j, c, msg)
|
||||
|
||||
msg = base_msg.format('return_index and return_inverse', dt)
|
||||
v, j1, j2 = unique(a, 1, 1, 0)
|
||||
assert_array_equal(v, b, msg)
|
||||
assert_array_equal(j1, i1, msg)
|
||||
assert_array_equal(j2, i2, msg)
|
||||
|
||||
msg = base_msg.format('return_index and return_counts', dt)
|
||||
v, j1, j2 = unique(a, 1, 0, 1)
|
||||
assert_array_equal(v, b, msg)
|
||||
assert_array_equal(j1, i1, msg)
|
||||
assert_array_equal(j2, c, msg)
|
||||
|
||||
msg = base_msg.format('return_inverse and return_counts', dt)
|
||||
v, j1, j2 = unique(a, 0, 1, 1)
|
||||
assert_array_equal(v, b, msg)
|
||||
assert_array_equal(j1, i2, msg)
|
||||
assert_array_equal(j2, c, msg)
|
||||
|
||||
msg = base_msg.format(('return_index, return_inverse '
|
||||
'and return_counts'), dt)
|
||||
v, j1, j2, j3 = unique(a, 1, 1, 1)
|
||||
assert_array_equal(v, b, msg)
|
||||
assert_array_equal(j1, i1, msg)
|
||||
assert_array_equal(j2, i2, msg)
|
||||
assert_array_equal(j3, c, msg)
|
||||
|
||||
a = [5, 7, 1, 2, 1, 5, 7]*10
|
||||
b = [1, 2, 5, 7]
|
||||
i1 = [2, 3, 0, 1]
|
||||
i2 = [2, 3, 0, 1, 0, 2, 3]*10
|
||||
c = np.multiply([2, 1, 2, 2], 10)
|
||||
|
||||
# test for numeric arrays
|
||||
types = []
|
||||
types.extend(np.typecodes['AllInteger'])
|
||||
types.extend(np.typecodes['AllFloat'])
|
||||
types.append('datetime64[D]')
|
||||
types.append('timedelta64[D]')
|
||||
for dt in types:
|
||||
aa = np.array(a, dt)
|
||||
bb = np.array(b, dt)
|
||||
check_all(aa, bb, i1, i2, c, dt)
|
||||
|
||||
# test for object arrays
|
||||
dt = 'O'
|
||||
aa = np.empty(len(a), dt)
|
||||
aa[:] = a
|
||||
bb = np.empty(len(b), dt)
|
||||
bb[:] = b
|
||||
check_all(aa, bb, i1, i2, c, dt)
|
||||
|
||||
# test for structured arrays
|
||||
dt = [('', 'i'), ('', 'i')]
|
||||
aa = np.array(list(zip(a, a)), dt)
|
||||
bb = np.array(list(zip(b, b)), dt)
|
||||
check_all(aa, bb, i1, i2, c, dt)
|
||||
|
||||
# test for ticket #2799
|
||||
aa = [1. + 0.j, 1 - 1.j, 1]
|
||||
assert_array_equal(np.unique(aa), [1. - 1.j, 1. + 0.j])
|
||||
|
||||
# test for ticket #4785
|
||||
a = [(1, 2), (1, 2), (2, 3)]
|
||||
unq = [1, 2, 3]
|
||||
inv = [0, 1, 0, 1, 1, 2]
|
||||
a1 = unique(a)
|
||||
assert_array_equal(a1, unq)
|
||||
a2, a2_inv = unique(a, return_inverse=True)
|
||||
assert_array_equal(a2, unq)
|
||||
assert_array_equal(a2_inv, inv)
|
||||
|
||||
# test for chararrays with return_inverse (gh-5099)
|
||||
a = np.chararray(5)
|
||||
a[...] = ''
|
||||
a2, a2_inv = np.unique(a, return_inverse=True)
|
||||
assert_array_equal(a2_inv, np.zeros(5))
|
||||
|
||||
# test for ticket #9137
|
||||
a = []
|
||||
a1_idx = np.unique(a, return_index=True)[1]
|
||||
a2_inv = np.unique(a, return_inverse=True)[1]
|
||||
a3_idx, a3_inv = np.unique(a, return_index=True, return_inverse=True)[1:]
|
||||
assert_equal(a1_idx.dtype, np.intp)
|
||||
assert_equal(a2_inv.dtype, np.intp)
|
||||
assert_equal(a3_idx.dtype, np.intp)
|
||||
assert_equal(a3_inv.dtype, np.intp)
|
||||
|
||||
def test_unique_axis_errors(self):
|
||||
assert_raises(TypeError, self._run_axis_tests, object)
|
||||
assert_raises(TypeError, self._run_axis_tests,
|
||||
[('a', int), ('b', object)])
|
||||
|
||||
assert_raises(np.AxisError, unique, np.arange(10), axis=2)
|
||||
assert_raises(np.AxisError, unique, np.arange(10), axis=-2)
|
||||
|
||||
def test_unique_axis_list(self):
|
||||
msg = "Unique failed on list of lists"
|
||||
inp = [[0, 1, 0], [0, 1, 0]]
|
||||
inp_arr = np.asarray(inp)
|
||||
assert_array_equal(unique(inp, axis=0), unique(inp_arr, axis=0), msg)
|
||||
assert_array_equal(unique(inp, axis=1), unique(inp_arr, axis=1), msg)
|
||||
|
||||
def test_unique_axis(self):
|
||||
types = []
|
||||
types.extend(np.typecodes['AllInteger'])
|
||||
types.extend(np.typecodes['AllFloat'])
|
||||
types.append('datetime64[D]')
|
||||
types.append('timedelta64[D]')
|
||||
types.append([('a', int), ('b', int)])
|
||||
types.append([('a', int), ('b', float)])
|
||||
|
||||
for dtype in types:
|
||||
self._run_axis_tests(dtype)
|
||||
|
||||
msg = 'Non-bitwise-equal booleans test failed'
|
||||
data = np.arange(10, dtype=np.uint8).reshape(-1, 2).view(bool)
|
||||
result = np.array([[False, True], [True, True]], dtype=bool)
|
||||
assert_array_equal(unique(data, axis=0), result, msg)
|
||||
|
||||
msg = 'Negative zero equality test failed'
|
||||
data = np.array([[-0.0, 0.0], [0.0, -0.0], [-0.0, 0.0], [0.0, -0.0]])
|
||||
result = np.array([[-0.0, 0.0]])
|
||||
assert_array_equal(unique(data, axis=0), result, msg)
|
||||
|
||||
def test_unique_masked(self):
|
||||
# issue 8664
|
||||
x = np.array([64, 0, 1, 2, 3, 63, 63, 0, 0, 0, 1, 2, 0, 63, 0], dtype='uint8')
|
||||
y = np.ma.masked_equal(x, 0)
|
||||
|
||||
v = np.unique(y)
|
||||
v2, i, c = np.unique(y, return_index=True, return_counts=True)
|
||||
|
||||
msg = 'Unique returned different results when asked for index'
|
||||
assert_array_equal(v.data, v2.data, msg)
|
||||
assert_array_equal(v.mask, v2.mask, msg)
|
||||
|
||||
def test_unique_sort_order_with_axis(self):
|
||||
# These tests fail if sorting along axis is done by treating subarrays
|
||||
# as unsigned byte strings. See gh-10495.
|
||||
fmt = "sort order incorrect for integer type '%s'"
|
||||
for dt in 'bhilq':
|
||||
a = np.array([[-1],[0]], dt)
|
||||
b = np.unique(a, axis=0)
|
||||
assert_array_equal(a, b, fmt % dt)
|
||||
|
||||
def _run_axis_tests(self, dtype):
|
||||
data = np.array([[0, 1, 0, 0],
|
||||
[1, 0, 0, 0],
|
||||
[0, 1, 0, 0],
|
||||
[1, 0, 0, 0]]).astype(dtype)
|
||||
|
||||
msg = 'Unique with 1d array and axis=0 failed'
|
||||
result = np.array([0, 1])
|
||||
assert_array_equal(unique(data), result.astype(dtype), msg)
|
||||
|
||||
msg = 'Unique with 2d array and axis=0 failed'
|
||||
result = np.array([[0, 1, 0, 0], [1, 0, 0, 0]])
|
||||
assert_array_equal(unique(data, axis=0), result.astype(dtype), msg)
|
||||
|
||||
msg = 'Unique with 2d array and axis=1 failed'
|
||||
result = np.array([[0, 0, 1], [0, 1, 0], [0, 0, 1], [0, 1, 0]])
|
||||
assert_array_equal(unique(data, axis=1), result.astype(dtype), msg)
|
||||
|
||||
msg = 'Unique with 3d array and axis=2 failed'
|
||||
data3d = np.dstack([data] * 3)
|
||||
result = data3d[..., :1]
|
||||
assert_array_equal(unique(data3d, axis=2), result, msg)
|
||||
|
||||
uniq, idx, inv, cnt = unique(data, axis=0, return_index=True,
|
||||
return_inverse=True, return_counts=True)
|
||||
msg = "Unique's return_index=True failed with axis=0"
|
||||
assert_array_equal(data[idx], uniq, msg)
|
||||
msg = "Unique's return_inverse=True failed with axis=0"
|
||||
assert_array_equal(uniq[inv], data)
|
||||
msg = "Unique's return_counts=True failed with axis=0"
|
||||
assert_array_equal(cnt, np.array([2, 2]), msg)
|
||||
|
||||
uniq, idx, inv, cnt = unique(data, axis=1, return_index=True,
|
||||
return_inverse=True, return_counts=True)
|
||||
msg = "Unique's return_index=True failed with axis=1"
|
||||
assert_array_equal(data[:, idx], uniq)
|
||||
msg = "Unique's return_inverse=True failed with axis=1"
|
||||
assert_array_equal(uniq[:, inv], data)
|
||||
msg = "Unique's return_counts=True failed with axis=1"
|
||||
assert_array_equal(cnt, np.array([2, 1, 1]), msg)
|
||||
@@ -0,0 +1,48 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
from operator import mul
|
||||
from functools import reduce
|
||||
|
||||
import numpy as np
|
||||
from numpy.random import randint
|
||||
from numpy.lib import Arrayterator
|
||||
from numpy.testing import assert_
|
||||
|
||||
|
||||
def test():
|
||||
np.random.seed(np.arange(10))
|
||||
|
||||
# Create a random array
|
||||
ndims = randint(5)+1
|
||||
shape = tuple(randint(10)+1 for dim in range(ndims))
|
||||
els = reduce(mul, shape)
|
||||
a = np.arange(els)
|
||||
a.shape = shape
|
||||
|
||||
buf_size = randint(2*els)
|
||||
b = Arrayterator(a, buf_size)
|
||||
|
||||
# Check that each block has at most ``buf_size`` elements
|
||||
for block in b:
|
||||
assert_(len(block.flat) <= (buf_size or els))
|
||||
|
||||
# Check that all elements are iterated correctly
|
||||
assert_(list(b.flat) == list(a.flat))
|
||||
|
||||
# Slice arrayterator
|
||||
start = [randint(dim) for dim in shape]
|
||||
stop = [randint(dim)+1 for dim in shape]
|
||||
step = [randint(dim)+1 for dim in shape]
|
||||
slice_ = tuple(slice(*t) for t in zip(start, stop, step))
|
||||
c = b[slice_]
|
||||
d = a[slice_]
|
||||
|
||||
# Check that each block has at most ``buf_size`` elements
|
||||
for block in c:
|
||||
assert_(len(block.flat) <= (buf_size or els))
|
||||
|
||||
# Check that the arrayterator is sliced correctly
|
||||
assert_(np.all(c.__array__() == d))
|
||||
|
||||
# Check that all elements are iterated correctly
|
||||
assert_(list(c.flat) == list(d.flat))
|
||||
@@ -0,0 +1,340 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
from decimal import Decimal
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import (
|
||||
assert_, assert_almost_equal, assert_allclose, assert_equal, assert_raises
|
||||
)
|
||||
|
||||
|
||||
class TestFinancial(object):
|
||||
def test_rate(self):
|
||||
assert_almost_equal(
|
||||
np.rate(10, 0, -3500, 10000),
|
||||
0.1107, 4)
|
||||
|
||||
def test_rate_decimal(self):
|
||||
rate = np.rate(Decimal('10'), Decimal('0'), Decimal('-3500'), Decimal('10000'))
|
||||
assert_equal(Decimal('0.1106908537142689284704528100'), rate)
|
||||
|
||||
def test_irr(self):
|
||||
v = [-150000, 15000, 25000, 35000, 45000, 60000]
|
||||
assert_almost_equal(np.irr(v), 0.0524, 2)
|
||||
v = [-100, 0, 0, 74]
|
||||
assert_almost_equal(np.irr(v), -0.0955, 2)
|
||||
v = [-100, 39, 59, 55, 20]
|
||||
assert_almost_equal(np.irr(v), 0.28095, 2)
|
||||
v = [-100, 100, 0, -7]
|
||||
assert_almost_equal(np.irr(v), -0.0833, 2)
|
||||
v = [-100, 100, 0, 7]
|
||||
assert_almost_equal(np.irr(v), 0.06206, 2)
|
||||
v = [-5, 10.5, 1, -8, 1]
|
||||
assert_almost_equal(np.irr(v), 0.0886, 2)
|
||||
|
||||
# Test that if there is no solution then np.irr returns nan
|
||||
# Fixes gh-6744
|
||||
v = [-1, -2, -3]
|
||||
assert_equal(np.irr(v), np.nan)
|
||||
|
||||
def test_pv(self):
|
||||
assert_almost_equal(np.pv(0.07, 20, 12000, 0), -127128.17, 2)
|
||||
|
||||
def test_pv_decimal(self):
|
||||
assert_equal(np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0')),
|
||||
Decimal('-127128.1709461939327295222005'))
|
||||
|
||||
def test_fv(self):
|
||||
assert_equal(np.fv(0.075, 20, -2000, 0, 0), 86609.362673042924)
|
||||
|
||||
def test_fv_decimal(self):
|
||||
assert_equal(np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), 0, 0),
|
||||
Decimal('86609.36267304300040536731624'))
|
||||
|
||||
def test_pmt(self):
|
||||
res = np.pmt(0.08 / 12, 5 * 12, 15000)
|
||||
tgt = -304.145914
|
||||
assert_allclose(res, tgt)
|
||||
# Test the edge case where rate == 0.0
|
||||
res = np.pmt(0.0, 5 * 12, 15000)
|
||||
tgt = -250.0
|
||||
assert_allclose(res, tgt)
|
||||
# Test the case where we use broadcast and
|
||||
# the arguments passed in are arrays.
|
||||
res = np.pmt([[0.0, 0.8], [0.3, 0.8]], [12, 3], [2000, 20000])
|
||||
tgt = np.array([[-166.66667, -19311.258], [-626.90814, -19311.258]])
|
||||
assert_allclose(res, tgt)
|
||||
|
||||
def test_pmt_decimal(self):
|
||||
res = np.pmt(Decimal('0.08') / Decimal('12'), 5 * 12, 15000)
|
||||
tgt = Decimal('-304.1459143262052370338701494')
|
||||
assert_equal(res, tgt)
|
||||
# Test the edge case where rate == 0.0
|
||||
res = np.pmt(Decimal('0'), Decimal('60'), Decimal('15000'))
|
||||
tgt = -250
|
||||
assert_equal(res, tgt)
|
||||
# Test the case where we use broadcast and
|
||||
# the arguments passed in are arrays.
|
||||
res = np.pmt([[Decimal('0'), Decimal('0.8')], [Decimal('0.3'), Decimal('0.8')]],
|
||||
[Decimal('12'), Decimal('3')], [Decimal('2000'), Decimal('20000')])
|
||||
tgt = np.array([[Decimal('-166.6666666666666666666666667'), Decimal('-19311.25827814569536423841060')],
|
||||
[Decimal('-626.9081401700757748402586600'), Decimal('-19311.25827814569536423841060')]])
|
||||
|
||||
# Cannot use the `assert_allclose` because it uses isfinite under the covers
|
||||
# which does not support the Decimal type
|
||||
# See issue: https://github.com/numpy/numpy/issues/9954
|
||||
assert_equal(res[0][0], tgt[0][0])
|
||||
assert_equal(res[0][1], tgt[0][1])
|
||||
assert_equal(res[1][0], tgt[1][0])
|
||||
assert_equal(res[1][1], tgt[1][1])
|
||||
|
||||
def test_ppmt(self):
|
||||
assert_equal(np.round(np.ppmt(0.1 / 12, 1, 60, 55000), 2), -710.25)
|
||||
|
||||
def test_ppmt_decimal(self):
|
||||
assert_equal(np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000')),
|
||||
Decimal('-710.2541257864217612489830917'))
|
||||
|
||||
# Two tests showing how Decimal is actually getting at a more exact result
|
||||
# .23 / 12 does not come out nicely as a float but does as a decimal
|
||||
def test_ppmt_special_rate(self):
|
||||
assert_equal(np.round(np.ppmt(0.23 / 12, 1, 60, 10000000000), 8), -90238044.232277036)
|
||||
|
||||
def test_ppmt_special_rate_decimal(self):
|
||||
# When rounded out to 8 decimal places like the float based test, this should not equal the same value
|
||||
# as the float, substituted for the decimal
|
||||
def raise_error_because_not_equal():
|
||||
assert_equal(
|
||||
round(np.ppmt(Decimal('0.23') / Decimal('12'), 1, 60, Decimal('10000000000')), 8),
|
||||
Decimal('-90238044.232277036'))
|
||||
|
||||
assert_raises(AssertionError, raise_error_because_not_equal)
|
||||
assert_equal(np.ppmt(Decimal('0.23') / Decimal('12'), 1, 60, Decimal('10000000000')),
|
||||
Decimal('-90238044.2322778884413969909'))
|
||||
|
||||
def test_ipmt(self):
|
||||
assert_almost_equal(np.round(np.ipmt(0.1 / 12, 1, 24, 2000), 2), -16.67)
|
||||
|
||||
def test_ipmt_decimal(self):
|
||||
result = np.ipmt(Decimal('0.1') / Decimal('12'), 1, 24, 2000)
|
||||
assert_equal(result.flat[0], Decimal('-16.66666666666666666666666667'))
|
||||
|
||||
def test_nper(self):
|
||||
assert_almost_equal(np.nper(0.075, -2000, 0, 100000.),
|
||||
21.54, 2)
|
||||
|
||||
def test_nper2(self):
|
||||
assert_almost_equal(np.nper(0.0, -2000, 0, 100000.),
|
||||
50.0, 1)
|
||||
|
||||
def test_npv(self):
|
||||
assert_almost_equal(
|
||||
np.npv(0.05, [-15000, 1500, 2500, 3500, 4500, 6000]),
|
||||
122.89, 2)
|
||||
|
||||
def test_npv_decimal(self):
|
||||
assert_equal(
|
||||
np.npv(Decimal('0.05'), [-15000, 1500, 2500, 3500, 4500, 6000]),
|
||||
Decimal('122.894854950942692161628715'))
|
||||
|
||||
def test_mirr(self):
|
||||
val = [-4500, -800, 800, 800, 600, 600, 800, 800, 700, 3000]
|
||||
assert_almost_equal(np.mirr(val, 0.08, 0.055), 0.0666, 4)
|
||||
|
||||
val = [-120000, 39000, 30000, 21000, 37000, 46000]
|
||||
assert_almost_equal(np.mirr(val, 0.10, 0.12), 0.126094, 6)
|
||||
|
||||
val = [100, 200, -50, 300, -200]
|
||||
assert_almost_equal(np.mirr(val, 0.05, 0.06), 0.3428, 4)
|
||||
|
||||
val = [39000, 30000, 21000, 37000, 46000]
|
||||
assert_(np.isnan(np.mirr(val, 0.10, 0.12)))
|
||||
|
||||
def test_mirr_decimal(self):
|
||||
val = [Decimal('-4500'), Decimal('-800'), Decimal('800'), Decimal('800'),
|
||||
Decimal('600'), Decimal('600'), Decimal('800'), Decimal('800'),
|
||||
Decimal('700'), Decimal('3000')]
|
||||
assert_equal(np.mirr(val, Decimal('0.08'), Decimal('0.055')),
|
||||
Decimal('0.066597175031553548874239618'))
|
||||
|
||||
val = [Decimal('-120000'), Decimal('39000'), Decimal('30000'),
|
||||
Decimal('21000'), Decimal('37000'), Decimal('46000')]
|
||||
assert_equal(np.mirr(val, Decimal('0.10'), Decimal('0.12')), Decimal('0.126094130365905145828421880'))
|
||||
|
||||
val = [Decimal('100'), Decimal('200'), Decimal('-50'),
|
||||
Decimal('300'), Decimal('-200')]
|
||||
assert_equal(np.mirr(val, Decimal('0.05'), Decimal('0.06')), Decimal('0.342823387842176663647819868'))
|
||||
|
||||
val = [Decimal('39000'), Decimal('30000'), Decimal('21000'), Decimal('37000'), Decimal('46000')]
|
||||
assert_(np.isnan(np.mirr(val, Decimal('0.10'), Decimal('0.12'))))
|
||||
|
||||
def test_when(self):
|
||||
# begin
|
||||
assert_equal(np.rate(10, 20, -3500, 10000, 1),
|
||||
np.rate(10, 20, -3500, 10000, 'begin'))
|
||||
# end
|
||||
assert_equal(np.rate(10, 20, -3500, 10000),
|
||||
np.rate(10, 20, -3500, 10000, 'end'))
|
||||
assert_equal(np.rate(10, 20, -3500, 10000, 0),
|
||||
np.rate(10, 20, -3500, 10000, 'end'))
|
||||
|
||||
# begin
|
||||
assert_equal(np.pv(0.07, 20, 12000, 0, 1),
|
||||
np.pv(0.07, 20, 12000, 0, 'begin'))
|
||||
# end
|
||||
assert_equal(np.pv(0.07, 20, 12000, 0),
|
||||
np.pv(0.07, 20, 12000, 0, 'end'))
|
||||
assert_equal(np.pv(0.07, 20, 12000, 0, 0),
|
||||
np.pv(0.07, 20, 12000, 0, 'end'))
|
||||
|
||||
# begin
|
||||
assert_equal(np.fv(0.075, 20, -2000, 0, 1),
|
||||
np.fv(0.075, 20, -2000, 0, 'begin'))
|
||||
# end
|
||||
assert_equal(np.fv(0.075, 20, -2000, 0),
|
||||
np.fv(0.075, 20, -2000, 0, 'end'))
|
||||
assert_equal(np.fv(0.075, 20, -2000, 0, 0),
|
||||
np.fv(0.075, 20, -2000, 0, 'end'))
|
||||
|
||||
# begin
|
||||
assert_equal(np.pmt(0.08 / 12, 5 * 12, 15000., 0, 1),
|
||||
np.pmt(0.08 / 12, 5 * 12, 15000., 0, 'begin'))
|
||||
# end
|
||||
assert_equal(np.pmt(0.08 / 12, 5 * 12, 15000., 0),
|
||||
np.pmt(0.08 / 12, 5 * 12, 15000., 0, 'end'))
|
||||
assert_equal(np.pmt(0.08 / 12, 5 * 12, 15000., 0, 0),
|
||||
np.pmt(0.08 / 12, 5 * 12, 15000., 0, 'end'))
|
||||
|
||||
# begin
|
||||
assert_equal(np.ppmt(0.1 / 12, 1, 60, 55000, 0, 1),
|
||||
np.ppmt(0.1 / 12, 1, 60, 55000, 0, 'begin'))
|
||||
# end
|
||||
assert_equal(np.ppmt(0.1 / 12, 1, 60, 55000, 0),
|
||||
np.ppmt(0.1 / 12, 1, 60, 55000, 0, 'end'))
|
||||
assert_equal(np.ppmt(0.1 / 12, 1, 60, 55000, 0, 0),
|
||||
np.ppmt(0.1 / 12, 1, 60, 55000, 0, 'end'))
|
||||
|
||||
# begin
|
||||
assert_equal(np.ipmt(0.1 / 12, 1, 24, 2000, 0, 1),
|
||||
np.ipmt(0.1 / 12, 1, 24, 2000, 0, 'begin'))
|
||||
# end
|
||||
assert_equal(np.ipmt(0.1 / 12, 1, 24, 2000, 0),
|
||||
np.ipmt(0.1 / 12, 1, 24, 2000, 0, 'end'))
|
||||
assert_equal(np.ipmt(0.1 / 12, 1, 24, 2000, 0, 0),
|
||||
np.ipmt(0.1 / 12, 1, 24, 2000, 0, 'end'))
|
||||
|
||||
# begin
|
||||
assert_equal(np.nper(0.075, -2000, 0, 100000., 1),
|
||||
np.nper(0.075, -2000, 0, 100000., 'begin'))
|
||||
# end
|
||||
assert_equal(np.nper(0.075, -2000, 0, 100000.),
|
||||
np.nper(0.075, -2000, 0, 100000., 'end'))
|
||||
assert_equal(np.nper(0.075, -2000, 0, 100000., 0),
|
||||
np.nper(0.075, -2000, 0, 100000., 'end'))
|
||||
|
||||
def test_decimal_with_when(self):
|
||||
"""Test that decimals are still supported if the when argument is passed"""
|
||||
# begin
|
||||
assert_equal(np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000'), Decimal('1')),
|
||||
np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000'), 'begin'))
|
||||
# end
|
||||
assert_equal(np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000')),
|
||||
np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000'), 'end'))
|
||||
assert_equal(np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000'), Decimal('0')),
|
||||
np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000'), 'end'))
|
||||
|
||||
# begin
|
||||
assert_equal(np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0'), Decimal('1')),
|
||||
np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0'), 'begin'))
|
||||
# end
|
||||
assert_equal(np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0')),
|
||||
np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0'), 'end'))
|
||||
assert_equal(np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0'), Decimal('0')),
|
||||
np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0'), 'end'))
|
||||
|
||||
# begin
|
||||
assert_equal(np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0'), Decimal('1')),
|
||||
np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0'), 'begin'))
|
||||
# end
|
||||
assert_equal(np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0')),
|
||||
np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0'), 'end'))
|
||||
assert_equal(np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0'), Decimal('0')),
|
||||
np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0'), 'end'))
|
||||
|
||||
# begin
|
||||
assert_equal(np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'),
|
||||
Decimal('0'), Decimal('1')),
|
||||
np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'),
|
||||
Decimal('0'), 'begin'))
|
||||
# end
|
||||
assert_equal(np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'),
|
||||
Decimal('0')),
|
||||
np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'),
|
||||
Decimal('0'), 'end'))
|
||||
assert_equal(np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'),
|
||||
Decimal('0'), Decimal('0')),
|
||||
np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'),
|
||||
Decimal('0'), 'end'))
|
||||
|
||||
# begin
|
||||
assert_equal(np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'),
|
||||
Decimal('0'), Decimal('1')),
|
||||
np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'),
|
||||
Decimal('0'), 'begin'))
|
||||
# end
|
||||
assert_equal(np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'),
|
||||
Decimal('0')),
|
||||
np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'),
|
||||
Decimal('0'), 'end'))
|
||||
assert_equal(np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'),
|
||||
Decimal('0'), Decimal('0')),
|
||||
np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'),
|
||||
Decimal('0'), 'end'))
|
||||
|
||||
# begin
|
||||
assert_equal(np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'),
|
||||
Decimal('0'), Decimal('1')).flat[0],
|
||||
np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'),
|
||||
Decimal('0'), 'begin').flat[0])
|
||||
# end
|
||||
assert_equal(np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'),
|
||||
Decimal('0')).flat[0],
|
||||
np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'),
|
||||
Decimal('0'), 'end').flat[0])
|
||||
assert_equal(np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'),
|
||||
Decimal('0'), Decimal('0')).flat[0],
|
||||
np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'),
|
||||
Decimal('0'), 'end').flat[0])
|
||||
|
||||
def test_broadcast(self):
|
||||
assert_almost_equal(np.nper(0.075, -2000, 0, 100000., [0, 1]),
|
||||
[21.5449442, 20.76156441], 4)
|
||||
|
||||
assert_almost_equal(np.ipmt(0.1 / 12, list(range(5)), 24, 2000),
|
||||
[-17.29165168, -16.66666667, -16.03647345,
|
||||
-15.40102862, -14.76028842], 4)
|
||||
|
||||
assert_almost_equal(np.ppmt(0.1 / 12, list(range(5)), 24, 2000),
|
||||
[-74.998201, -75.62318601, -76.25337923,
|
||||
-76.88882405, -77.52956425], 4)
|
||||
|
||||
assert_almost_equal(np.ppmt(0.1 / 12, list(range(5)), 24, 2000, 0,
|
||||
[0, 0, 1, 'end', 'begin']),
|
||||
[-74.998201, -75.62318601, -75.62318601,
|
||||
-76.88882405, -76.88882405], 4)
|
||||
|
||||
def test_broadcast_decimal(self):
|
||||
# Use almost equal because precision is tested in the explicit tests, this test is to ensure
|
||||
# broadcast with Decimal is not broken.
|
||||
assert_almost_equal(np.ipmt(Decimal('0.1') / Decimal('12'), list(range(5)), Decimal('24'), Decimal('2000')),
|
||||
[Decimal('-17.29165168'), Decimal('-16.66666667'), Decimal('-16.03647345'),
|
||||
Decimal('-15.40102862'), Decimal('-14.76028842')], 4)
|
||||
|
||||
assert_almost_equal(np.ppmt(Decimal('0.1') / Decimal('12'), list(range(5)), Decimal('24'), Decimal('2000')),
|
||||
[Decimal('-74.998201'), Decimal('-75.62318601'), Decimal('-76.25337923'),
|
||||
Decimal('-76.88882405'), Decimal('-77.52956425')], 4)
|
||||
|
||||
assert_almost_equal(np.ppmt(Decimal('0.1') / Decimal('12'), list(range(5)), Decimal('24'), Decimal('2000'),
|
||||
Decimal('0'), [Decimal('0'), Decimal('0'), Decimal('1'), 'end', 'begin']),
|
||||
[Decimal('-74.998201'), Decimal('-75.62318601'), Decimal('-75.62318601'),
|
||||
Decimal('-76.88882405'), Decimal('-76.88882405')], 4)
|
||||
@@ -0,0 +1,881 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
# doctest
|
||||
r''' Test the .npy file format.
|
||||
|
||||
Set up:
|
||||
|
||||
>>> import sys
|
||||
>>> from io import BytesIO
|
||||
>>> from numpy.lib import format
|
||||
>>>
|
||||
>>> scalars = [
|
||||
... np.uint8,
|
||||
... np.int8,
|
||||
... np.uint16,
|
||||
... np.int16,
|
||||
... np.uint32,
|
||||
... np.int32,
|
||||
... np.uint64,
|
||||
... np.int64,
|
||||
... np.float32,
|
||||
... np.float64,
|
||||
... np.complex64,
|
||||
... np.complex128,
|
||||
... object,
|
||||
... ]
|
||||
>>>
|
||||
>>> basic_arrays = []
|
||||
>>>
|
||||
>>> for scalar in scalars:
|
||||
... for endian in '<>':
|
||||
... dtype = np.dtype(scalar).newbyteorder(endian)
|
||||
... basic = np.arange(15).astype(dtype)
|
||||
... basic_arrays.extend([
|
||||
... np.array([], dtype=dtype),
|
||||
... np.array(10, dtype=dtype),
|
||||
... basic,
|
||||
... basic.reshape((3,5)),
|
||||
... basic.reshape((3,5)).T,
|
||||
... basic.reshape((3,5))[::-1,::2],
|
||||
... ])
|
||||
...
|
||||
>>>
|
||||
>>> Pdescr = [
|
||||
... ('x', 'i4', (2,)),
|
||||
... ('y', 'f8', (2, 2)),
|
||||
... ('z', 'u1')]
|
||||
>>>
|
||||
>>>
|
||||
>>> PbufferT = [
|
||||
... ([3,2], [[6.,4.],[6.,4.]], 8),
|
||||
... ([4,3], [[7.,5.],[7.,5.]], 9),
|
||||
... ]
|
||||
>>>
|
||||
>>>
|
||||
>>> Ndescr = [
|
||||
... ('x', 'i4', (2,)),
|
||||
... ('Info', [
|
||||
... ('value', 'c16'),
|
||||
... ('y2', 'f8'),
|
||||
... ('Info2', [
|
||||
... ('name', 'S2'),
|
||||
... ('value', 'c16', (2,)),
|
||||
... ('y3', 'f8', (2,)),
|
||||
... ('z3', 'u4', (2,))]),
|
||||
... ('name', 'S2'),
|
||||
... ('z2', 'b1')]),
|
||||
... ('color', 'S2'),
|
||||
... ('info', [
|
||||
... ('Name', 'U8'),
|
||||
... ('Value', 'c16')]),
|
||||
... ('y', 'f8', (2, 2)),
|
||||
... ('z', 'u1')]
|
||||
>>>
|
||||
>>>
|
||||
>>> NbufferT = [
|
||||
... ([3,2], (6j, 6., ('nn', [6j,4j], [6.,4.], [1,2]), 'NN', True), 'cc', ('NN', 6j), [[6.,4.],[6.,4.]], 8),
|
||||
... ([4,3], (7j, 7., ('oo', [7j,5j], [7.,5.], [2,1]), 'OO', False), 'dd', ('OO', 7j), [[7.,5.],[7.,5.]], 9),
|
||||
... ]
|
||||
>>>
|
||||
>>>
|
||||
>>> record_arrays = [
|
||||
... np.array(PbufferT, dtype=np.dtype(Pdescr).newbyteorder('<')),
|
||||
... np.array(NbufferT, dtype=np.dtype(Ndescr).newbyteorder('<')),
|
||||
... np.array(PbufferT, dtype=np.dtype(Pdescr).newbyteorder('>')),
|
||||
... np.array(NbufferT, dtype=np.dtype(Ndescr).newbyteorder('>')),
|
||||
... ]
|
||||
|
||||
Test the magic string writing.
|
||||
|
||||
>>> format.magic(1, 0)
|
||||
'\x93NUMPY\x01\x00'
|
||||
>>> format.magic(0, 0)
|
||||
'\x93NUMPY\x00\x00'
|
||||
>>> format.magic(255, 255)
|
||||
'\x93NUMPY\xff\xff'
|
||||
>>> format.magic(2, 5)
|
||||
'\x93NUMPY\x02\x05'
|
||||
|
||||
Test the magic string reading.
|
||||
|
||||
>>> format.read_magic(BytesIO(format.magic(1, 0)))
|
||||
(1, 0)
|
||||
>>> format.read_magic(BytesIO(format.magic(0, 0)))
|
||||
(0, 0)
|
||||
>>> format.read_magic(BytesIO(format.magic(255, 255)))
|
||||
(255, 255)
|
||||
>>> format.read_magic(BytesIO(format.magic(2, 5)))
|
||||
(2, 5)
|
||||
|
||||
Test the header writing.
|
||||
|
||||
>>> for arr in basic_arrays + record_arrays:
|
||||
... f = BytesIO()
|
||||
... format.write_array_header_1_0(f, arr) # XXX: arr is not a dict, items gets called on it
|
||||
... print(repr(f.getvalue()))
|
||||
...
|
||||
"F\x00{'descr': '|u1', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '|u1', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '|u1', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '|u1', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '|u1', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '|u1', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '|u1', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '|u1', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '|u1', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '|u1', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '|u1', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '|u1', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '|i1', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '|i1', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '|i1', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '|i1', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '|i1', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '|i1', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '|i1', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '|i1', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '|i1', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '|i1', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '|i1', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '|i1', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '<u2', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '<u2', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '<u2', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '<u2', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '<u2', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '<u2', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '>u2', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '>u2', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '>u2', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '>u2', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '>u2', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '>u2', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '<i2', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '<i2', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '<i2', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '<i2', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '<i2', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '<i2', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '>i2', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '>i2', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '>i2', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '>i2', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '>i2', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '>i2', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '<u4', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '<u4', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '<u4', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '<u4', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '<u4', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '<u4', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '>u4', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '>u4', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '>u4', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '>u4', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '>u4', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '>u4', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '<i4', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '<i4', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '<i4', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '<i4', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '<i4', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '<i4', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '>i4', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '>i4', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '>i4', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '>i4', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '>i4', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '>i4', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '<u8', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '<u8', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '<u8', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '<u8', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '<u8', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '<u8', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '>u8', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '>u8', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '>u8', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '>u8', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '>u8', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '>u8', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '<i8', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '<i8', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '<i8', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '<i8', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '<i8', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '<i8', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '>i8', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '>i8', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '>i8', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '>i8', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '>i8', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '>i8', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '<f4', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '<f4', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '<f4', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '<f4', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '<f4', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '<f4', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '>f4', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '>f4', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '>f4', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '>f4', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '>f4', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '>f4', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '<f8', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '<f8', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '<f8', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '<f8', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '<f8', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '<f8', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '>f8', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '>f8', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '>f8', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '>f8', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '>f8', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '>f8', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '<c8', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '<c8', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '<c8', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '<c8', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '<c8', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '<c8', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '>c8', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '>c8', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '>c8', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '>c8', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '>c8', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '>c8', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '<c16', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '<c16', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '<c16', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '<c16', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '<c16', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '<c16', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': '>c16', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': '>c16', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': '>c16', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': '>c16', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': '>c16', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': '>c16', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': 'O', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': 'O', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': 'O', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': 'O', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': 'O', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': 'O', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"F\x00{'descr': 'O', 'fortran_order': False, 'shape': (0,)} \n"
|
||||
"F\x00{'descr': 'O', 'fortran_order': False, 'shape': ()} \n"
|
||||
"F\x00{'descr': 'O', 'fortran_order': False, 'shape': (15,)} \n"
|
||||
"F\x00{'descr': 'O', 'fortran_order': False, 'shape': (3, 5)} \n"
|
||||
"F\x00{'descr': 'O', 'fortran_order': True, 'shape': (5, 3)} \n"
|
||||
"F\x00{'descr': 'O', 'fortran_order': False, 'shape': (3, 3)} \n"
|
||||
"v\x00{'descr': [('x', '<i4', (2,)), ('y', '<f8', (2, 2)), ('z', '|u1')],\n 'fortran_order': False,\n 'shape': (2,)} \n"
|
||||
"\x16\x02{'descr': [('x', '<i4', (2,)),\n ('Info',\n [('value', '<c16'),\n ('y2', '<f8'),\n ('Info2',\n [('name', '|S2'),\n ('value', '<c16', (2,)),\n ('y3', '<f8', (2,)),\n ('z3', '<u4', (2,))]),\n ('name', '|S2'),\n ('z2', '|b1')]),\n ('color', '|S2'),\n ('info', [('Name', '<U8'), ('Value', '<c16')]),\n ('y', '<f8', (2, 2)),\n ('z', '|u1')],\n 'fortran_order': False,\n 'shape': (2,)} \n"
|
||||
"v\x00{'descr': [('x', '>i4', (2,)), ('y', '>f8', (2, 2)), ('z', '|u1')],\n 'fortran_order': False,\n 'shape': (2,)} \n"
|
||||
"\x16\x02{'descr': [('x', '>i4', (2,)),\n ('Info',\n [('value', '>c16'),\n ('y2', '>f8'),\n ('Info2',\n [('name', '|S2'),\n ('value', '>c16', (2,)),\n ('y3', '>f8', (2,)),\n ('z3', '>u4', (2,))]),\n ('name', '|S2'),\n ('z2', '|b1')]),\n ('color', '|S2'),\n ('info', [('Name', '>U8'), ('Value', '>c16')]),\n ('y', '>f8', (2, 2)),\n ('z', '|u1')],\n 'fortran_order': False,\n 'shape': (2,)} \n"
|
||||
'''
|
||||
import sys
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import warnings
|
||||
import pytest
|
||||
from io import BytesIO
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import (
|
||||
assert_, assert_array_equal, assert_raises, assert_raises_regex,
|
||||
)
|
||||
from numpy.lib import format
|
||||
|
||||
|
||||
tempdir = None
|
||||
|
||||
# Module-level setup.
|
||||
|
||||
|
||||
def setup_module():
|
||||
global tempdir
|
||||
tempdir = tempfile.mkdtemp()
|
||||
|
||||
|
||||
def teardown_module():
|
||||
global tempdir
|
||||
if tempdir is not None and os.path.isdir(tempdir):
|
||||
shutil.rmtree(tempdir)
|
||||
tempdir = None
|
||||
|
||||
|
||||
# Generate some basic arrays to test with.
|
||||
scalars = [
|
||||
np.uint8,
|
||||
np.int8,
|
||||
np.uint16,
|
||||
np.int16,
|
||||
np.uint32,
|
||||
np.int32,
|
||||
np.uint64,
|
||||
np.int64,
|
||||
np.float32,
|
||||
np.float64,
|
||||
np.complex64,
|
||||
np.complex128,
|
||||
object,
|
||||
]
|
||||
basic_arrays = []
|
||||
for scalar in scalars:
|
||||
for endian in '<>':
|
||||
dtype = np.dtype(scalar).newbyteorder(endian)
|
||||
basic = np.arange(1500).astype(dtype)
|
||||
basic_arrays.extend([
|
||||
# Empty
|
||||
np.array([], dtype=dtype),
|
||||
# Rank-0
|
||||
np.array(10, dtype=dtype),
|
||||
# 1-D
|
||||
basic,
|
||||
# 2-D C-contiguous
|
||||
basic.reshape((30, 50)),
|
||||
# 2-D F-contiguous
|
||||
basic.reshape((30, 50)).T,
|
||||
# 2-D non-contiguous
|
||||
basic.reshape((30, 50))[::-1, ::2],
|
||||
])
|
||||
|
||||
# More complicated record arrays.
|
||||
# This is the structure of the table used for plain objects:
|
||||
#
|
||||
# +-+-+-+
|
||||
# |x|y|z|
|
||||
# +-+-+-+
|
||||
|
||||
# Structure of a plain array description:
|
||||
Pdescr = [
|
||||
('x', 'i4', (2,)),
|
||||
('y', 'f8', (2, 2)),
|
||||
('z', 'u1')]
|
||||
|
||||
# A plain list of tuples with values for testing:
|
||||
PbufferT = [
|
||||
# x y z
|
||||
([3, 2], [[6., 4.], [6., 4.]], 8),
|
||||
([4, 3], [[7., 5.], [7., 5.]], 9),
|
||||
]
|
||||
|
||||
|
||||
# This is the structure of the table used for nested objects (DON'T PANIC!):
|
||||
#
|
||||
# +-+---------------------------------+-----+----------+-+-+
|
||||
# |x|Info |color|info |y|z|
|
||||
# | +-----+--+----------------+----+--+ +----+-----+ | |
|
||||
# | |value|y2|Info2 |name|z2| |Name|Value| | |
|
||||
# | | | +----+-----+--+--+ | | | | | | |
|
||||
# | | | |name|value|y3|z3| | | | | | | |
|
||||
# +-+-----+--+----+-----+--+--+----+--+-----+----+-----+-+-+
|
||||
#
|
||||
|
||||
# The corresponding nested array description:
|
||||
Ndescr = [
|
||||
('x', 'i4', (2,)),
|
||||
('Info', [
|
||||
('value', 'c16'),
|
||||
('y2', 'f8'),
|
||||
('Info2', [
|
||||
('name', 'S2'),
|
||||
('value', 'c16', (2,)),
|
||||
('y3', 'f8', (2,)),
|
||||
('z3', 'u4', (2,))]),
|
||||
('name', 'S2'),
|
||||
('z2', 'b1')]),
|
||||
('color', 'S2'),
|
||||
('info', [
|
||||
('Name', 'U8'),
|
||||
('Value', 'c16')]),
|
||||
('y', 'f8', (2, 2)),
|
||||
('z', 'u1')]
|
||||
|
||||
NbufferT = [
|
||||
# x Info color info y z
|
||||
# value y2 Info2 name z2 Name Value
|
||||
# name value y3 z3
|
||||
([3, 2], (6j, 6., ('nn', [6j, 4j], [6., 4.], [1, 2]), 'NN', True),
|
||||
'cc', ('NN', 6j), [[6., 4.], [6., 4.]], 8),
|
||||
([4, 3], (7j, 7., ('oo', [7j, 5j], [7., 5.], [2, 1]), 'OO', False),
|
||||
'dd', ('OO', 7j), [[7., 5.], [7., 5.]], 9),
|
||||
]
|
||||
|
||||
record_arrays = [
|
||||
np.array(PbufferT, dtype=np.dtype(Pdescr).newbyteorder('<')),
|
||||
np.array(NbufferT, dtype=np.dtype(Ndescr).newbyteorder('<')),
|
||||
np.array(PbufferT, dtype=np.dtype(Pdescr).newbyteorder('>')),
|
||||
np.array(NbufferT, dtype=np.dtype(Ndescr).newbyteorder('>')),
|
||||
]
|
||||
|
||||
|
||||
#BytesIO that reads a random number of bytes at a time
|
||||
class BytesIOSRandomSize(BytesIO):
|
||||
def read(self, size=None):
|
||||
import random
|
||||
size = random.randint(1, size)
|
||||
return super(BytesIOSRandomSize, self).read(size)
|
||||
|
||||
|
||||
def roundtrip(arr):
|
||||
f = BytesIO()
|
||||
format.write_array(f, arr)
|
||||
f2 = BytesIO(f.getvalue())
|
||||
arr2 = format.read_array(f2)
|
||||
return arr2
|
||||
|
||||
|
||||
def roundtrip_randsize(arr):
|
||||
f = BytesIO()
|
||||
format.write_array(f, arr)
|
||||
f2 = BytesIOSRandomSize(f.getvalue())
|
||||
arr2 = format.read_array(f2)
|
||||
return arr2
|
||||
|
||||
|
||||
def roundtrip_truncated(arr):
|
||||
f = BytesIO()
|
||||
format.write_array(f, arr)
|
||||
#BytesIO is one byte short
|
||||
f2 = BytesIO(f.getvalue()[0:-1])
|
||||
arr2 = format.read_array(f2)
|
||||
return arr2
|
||||
|
||||
|
||||
def assert_equal_(o1, o2):
|
||||
assert_(o1 == o2)
|
||||
|
||||
|
||||
def test_roundtrip():
|
||||
for arr in basic_arrays + record_arrays:
|
||||
arr2 = roundtrip(arr)
|
||||
assert_array_equal(arr, arr2)
|
||||
|
||||
|
||||
def test_roundtrip_randsize():
|
||||
for arr in basic_arrays + record_arrays:
|
||||
if arr.dtype != object:
|
||||
arr2 = roundtrip_randsize(arr)
|
||||
assert_array_equal(arr, arr2)
|
||||
|
||||
|
||||
def test_roundtrip_truncated():
|
||||
for arr in basic_arrays:
|
||||
if arr.dtype != object:
|
||||
assert_raises(ValueError, roundtrip_truncated, arr)
|
||||
|
||||
|
||||
def test_long_str():
|
||||
# check items larger than internal buffer size, gh-4027
|
||||
long_str_arr = np.ones(1, dtype=np.dtype((str, format.BUFFER_SIZE + 1)))
|
||||
long_str_arr2 = roundtrip(long_str_arr)
|
||||
assert_array_equal(long_str_arr, long_str_arr2)
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_memmap_roundtrip():
|
||||
# Fixme: used to crash on windows
|
||||
if not (sys.platform == 'win32' or sys.platform == 'cygwin'):
|
||||
for arr in basic_arrays + record_arrays:
|
||||
if arr.dtype.hasobject:
|
||||
# Skip these since they can't be mmap'ed.
|
||||
continue
|
||||
# Write it out normally and through mmap.
|
||||
nfn = os.path.join(tempdir, 'normal.npy')
|
||||
mfn = os.path.join(tempdir, 'memmap.npy')
|
||||
fp = open(nfn, 'wb')
|
||||
try:
|
||||
format.write_array(fp, arr)
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
fortran_order = (
|
||||
arr.flags.f_contiguous and not arr.flags.c_contiguous)
|
||||
ma = format.open_memmap(mfn, mode='w+', dtype=arr.dtype,
|
||||
shape=arr.shape, fortran_order=fortran_order)
|
||||
ma[...] = arr
|
||||
del ma
|
||||
|
||||
# Check that both of these files' contents are the same.
|
||||
fp = open(nfn, 'rb')
|
||||
normal_bytes = fp.read()
|
||||
fp.close()
|
||||
fp = open(mfn, 'rb')
|
||||
memmap_bytes = fp.read()
|
||||
fp.close()
|
||||
assert_equal_(normal_bytes, memmap_bytes)
|
||||
|
||||
# Check that reading the file using memmap works.
|
||||
ma = format.open_memmap(nfn, mode='r')
|
||||
del ma
|
||||
|
||||
|
||||
def test_compressed_roundtrip():
|
||||
arr = np.random.rand(200, 200)
|
||||
npz_file = os.path.join(tempdir, 'compressed.npz')
|
||||
np.savez_compressed(npz_file, arr=arr)
|
||||
arr1 = np.load(npz_file)['arr']
|
||||
assert_array_equal(arr, arr1)
|
||||
|
||||
|
||||
# aligned
|
||||
dt1 = np.dtype('i1, i4, i1', align=True)
|
||||
# non-aligned, explicit offsets
|
||||
dt2 = np.dtype({'names': ['a', 'b'], 'formats': ['i4', 'i4'],
|
||||
'offsets': [1, 6]})
|
||||
# nested struct-in-struct
|
||||
dt3 = np.dtype({'names': ['c', 'd'], 'formats': ['i4', dt2]})
|
||||
# field with '' name
|
||||
dt4 = np.dtype({'names': ['a', '', 'b'], 'formats': ['i4']*3})
|
||||
# titles
|
||||
dt5 = np.dtype({'names': ['a', 'b'], 'formats': ['i4', 'i4'],
|
||||
'offsets': [1, 6], 'titles': ['aa', 'bb']})
|
||||
|
||||
@pytest.mark.parametrize("dt", [dt1, dt2, dt3, dt4, dt5])
|
||||
def test_load_padded_dtype(dt):
|
||||
arr = np.zeros(3, dt)
|
||||
for i in range(3):
|
||||
arr[i] = i + 5
|
||||
npz_file = os.path.join(tempdir, 'aligned.npz')
|
||||
np.savez(npz_file, arr=arr)
|
||||
arr1 = np.load(npz_file)['arr']
|
||||
assert_array_equal(arr, arr1)
|
||||
|
||||
|
||||
def test_python2_python3_interoperability():
|
||||
if sys.version_info[0] >= 3:
|
||||
fname = 'win64python2.npy'
|
||||
else:
|
||||
fname = 'python3.npy'
|
||||
path = os.path.join(os.path.dirname(__file__), 'data', fname)
|
||||
data = np.load(path)
|
||||
assert_array_equal(data, np.ones(2))
|
||||
|
||||
def test_pickle_python2_python3():
|
||||
# Test that loading object arrays saved on Python 2 works both on
|
||||
# Python 2 and Python 3 and vice versa
|
||||
data_dir = os.path.join(os.path.dirname(__file__), 'data')
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
xrange = range
|
||||
else:
|
||||
import __builtin__
|
||||
xrange = __builtin__.xrange
|
||||
|
||||
expected = np.array([None, xrange, u'\u512a\u826f',
|
||||
b'\xe4\xb8\x8d\xe8\x89\xaf'],
|
||||
dtype=object)
|
||||
|
||||
for fname in ['py2-objarr.npy', 'py2-objarr.npz',
|
||||
'py3-objarr.npy', 'py3-objarr.npz']:
|
||||
path = os.path.join(data_dir, fname)
|
||||
|
||||
for encoding in ['bytes', 'latin1']:
|
||||
data_f = np.load(path, encoding=encoding)
|
||||
if fname.endswith('.npz'):
|
||||
data = data_f['x']
|
||||
data_f.close()
|
||||
else:
|
||||
data = data_f
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
if encoding == 'latin1' and fname.startswith('py2'):
|
||||
assert_(isinstance(data[3], str))
|
||||
assert_array_equal(data[:-1], expected[:-1])
|
||||
# mojibake occurs
|
||||
assert_array_equal(data[-1].encode(encoding), expected[-1])
|
||||
else:
|
||||
assert_(isinstance(data[3], bytes))
|
||||
assert_array_equal(data, expected)
|
||||
else:
|
||||
assert_array_equal(data, expected)
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
if fname.startswith('py2'):
|
||||
if fname.endswith('.npz'):
|
||||
data = np.load(path)
|
||||
assert_raises(UnicodeError, data.__getitem__, 'x')
|
||||
data.close()
|
||||
data = np.load(path, fix_imports=False, encoding='latin1')
|
||||
assert_raises(ImportError, data.__getitem__, 'x')
|
||||
data.close()
|
||||
else:
|
||||
assert_raises(UnicodeError, np.load, path)
|
||||
assert_raises(ImportError, np.load, path,
|
||||
encoding='latin1', fix_imports=False)
|
||||
|
||||
|
||||
def test_pickle_disallow():
|
||||
data_dir = os.path.join(os.path.dirname(__file__), 'data')
|
||||
|
||||
path = os.path.join(data_dir, 'py2-objarr.npy')
|
||||
assert_raises(ValueError, np.load, path,
|
||||
allow_pickle=False, encoding='latin1')
|
||||
|
||||
path = os.path.join(data_dir, 'py2-objarr.npz')
|
||||
f = np.load(path, allow_pickle=False, encoding='latin1')
|
||||
assert_raises(ValueError, f.__getitem__, 'x')
|
||||
|
||||
path = os.path.join(tempdir, 'pickle-disabled.npy')
|
||||
assert_raises(ValueError, np.save, path, np.array([None], dtype=object),
|
||||
allow_pickle=False)
|
||||
|
||||
|
||||
def test_version_2_0():
|
||||
f = BytesIO()
|
||||
# requires more than 2 byte for header
|
||||
dt = [(("%d" % i) * 100, float) for i in range(500)]
|
||||
d = np.ones(1000, dtype=dt)
|
||||
|
||||
format.write_array(f, d, version=(2, 0))
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.filterwarnings('always', '', UserWarning)
|
||||
format.write_array(f, d)
|
||||
assert_(w[0].category is UserWarning)
|
||||
|
||||
# check alignment of data portion
|
||||
f.seek(0)
|
||||
header = f.readline()
|
||||
assert_(len(header) % format.ARRAY_ALIGN == 0)
|
||||
|
||||
f.seek(0)
|
||||
n = format.read_array(f)
|
||||
assert_array_equal(d, n)
|
||||
|
||||
# 1.0 requested but data cannot be saved this way
|
||||
assert_raises(ValueError, format.write_array, f, d, (1, 0))
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_version_2_0_memmap():
|
||||
# requires more than 2 byte for header
|
||||
dt = [(("%d" % i) * 100, float) for i in range(500)]
|
||||
d = np.ones(1000, dtype=dt)
|
||||
tf = tempfile.mktemp('', 'mmap', dir=tempdir)
|
||||
|
||||
# 1.0 requested but data cannot be saved this way
|
||||
assert_raises(ValueError, format.open_memmap, tf, mode='w+', dtype=d.dtype,
|
||||
shape=d.shape, version=(1, 0))
|
||||
|
||||
ma = format.open_memmap(tf, mode='w+', dtype=d.dtype,
|
||||
shape=d.shape, version=(2, 0))
|
||||
ma[...] = d
|
||||
del ma
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.filterwarnings('always', '', UserWarning)
|
||||
ma = format.open_memmap(tf, mode='w+', dtype=d.dtype,
|
||||
shape=d.shape, version=None)
|
||||
assert_(w[0].category is UserWarning)
|
||||
ma[...] = d
|
||||
del ma
|
||||
|
||||
ma = format.open_memmap(tf, mode='r')
|
||||
assert_array_equal(ma, d)
|
||||
|
||||
|
||||
def test_write_version():
|
||||
f = BytesIO()
|
||||
arr = np.arange(1)
|
||||
# These should pass.
|
||||
format.write_array(f, arr, version=(1, 0))
|
||||
format.write_array(f, arr)
|
||||
|
||||
format.write_array(f, arr, version=None)
|
||||
format.write_array(f, arr)
|
||||
|
||||
format.write_array(f, arr, version=(2, 0))
|
||||
format.write_array(f, arr)
|
||||
|
||||
# These should all fail.
|
||||
bad_versions = [
|
||||
(1, 1),
|
||||
(0, 0),
|
||||
(0, 1),
|
||||
(2, 2),
|
||||
(255, 255),
|
||||
]
|
||||
for version in bad_versions:
|
||||
with assert_raises_regex(ValueError,
|
||||
'we only support format version.*'):
|
||||
format.write_array(f, arr, version=version)
|
||||
|
||||
|
||||
bad_version_magic = [
|
||||
b'\x93NUMPY\x01\x01',
|
||||
b'\x93NUMPY\x00\x00',
|
||||
b'\x93NUMPY\x00\x01',
|
||||
b'\x93NUMPY\x02\x00',
|
||||
b'\x93NUMPY\x02\x02',
|
||||
b'\x93NUMPY\xff\xff',
|
||||
]
|
||||
malformed_magic = [
|
||||
b'\x92NUMPY\x01\x00',
|
||||
b'\x00NUMPY\x01\x00',
|
||||
b'\x93numpy\x01\x00',
|
||||
b'\x93MATLB\x01\x00',
|
||||
b'\x93NUMPY\x01',
|
||||
b'\x93NUMPY',
|
||||
b'',
|
||||
]
|
||||
|
||||
def test_read_magic():
|
||||
s1 = BytesIO()
|
||||
s2 = BytesIO()
|
||||
|
||||
arr = np.ones((3, 6), dtype=float)
|
||||
|
||||
format.write_array(s1, arr, version=(1, 0))
|
||||
format.write_array(s2, arr, version=(2, 0))
|
||||
|
||||
s1.seek(0)
|
||||
s2.seek(0)
|
||||
|
||||
version1 = format.read_magic(s1)
|
||||
version2 = format.read_magic(s2)
|
||||
|
||||
assert_(version1 == (1, 0))
|
||||
assert_(version2 == (2, 0))
|
||||
|
||||
assert_(s1.tell() == format.MAGIC_LEN)
|
||||
assert_(s2.tell() == format.MAGIC_LEN)
|
||||
|
||||
def test_read_magic_bad_magic():
|
||||
for magic in malformed_magic:
|
||||
f = BytesIO(magic)
|
||||
assert_raises(ValueError, format.read_array, f)
|
||||
|
||||
|
||||
def test_read_version_1_0_bad_magic():
|
||||
for magic in bad_version_magic + malformed_magic:
|
||||
f = BytesIO(magic)
|
||||
assert_raises(ValueError, format.read_array, f)
|
||||
|
||||
|
||||
def test_bad_magic_args():
|
||||
assert_raises(ValueError, format.magic, -1, 1)
|
||||
assert_raises(ValueError, format.magic, 256, 1)
|
||||
assert_raises(ValueError, format.magic, 1, -1)
|
||||
assert_raises(ValueError, format.magic, 1, 256)
|
||||
|
||||
|
||||
def test_large_header():
|
||||
s = BytesIO()
|
||||
d = {'a': 1, 'b': 2}
|
||||
format.write_array_header_1_0(s, d)
|
||||
|
||||
s = BytesIO()
|
||||
d = {'a': 1, 'b': 2, 'c': 'x'*256*256}
|
||||
assert_raises(ValueError, format.write_array_header_1_0, s, d)
|
||||
|
||||
|
||||
def test_read_array_header_1_0():
|
||||
s = BytesIO()
|
||||
|
||||
arr = np.ones((3, 6), dtype=float)
|
||||
format.write_array(s, arr, version=(1, 0))
|
||||
|
||||
s.seek(format.MAGIC_LEN)
|
||||
shape, fortran, dtype = format.read_array_header_1_0(s)
|
||||
|
||||
assert_(s.tell() % format.ARRAY_ALIGN == 0)
|
||||
assert_((shape, fortran, dtype) == ((3, 6), False, float))
|
||||
|
||||
|
||||
def test_read_array_header_2_0():
|
||||
s = BytesIO()
|
||||
|
||||
arr = np.ones((3, 6), dtype=float)
|
||||
format.write_array(s, arr, version=(2, 0))
|
||||
|
||||
s.seek(format.MAGIC_LEN)
|
||||
shape, fortran, dtype = format.read_array_header_2_0(s)
|
||||
|
||||
assert_(s.tell() % format.ARRAY_ALIGN == 0)
|
||||
assert_((shape, fortran, dtype) == ((3, 6), False, float))
|
||||
|
||||
|
||||
def test_bad_header():
|
||||
# header of length less than 2 should fail
|
||||
s = BytesIO()
|
||||
assert_raises(ValueError, format.read_array_header_1_0, s)
|
||||
s = BytesIO(b'1')
|
||||
assert_raises(ValueError, format.read_array_header_1_0, s)
|
||||
|
||||
# header shorter than indicated size should fail
|
||||
s = BytesIO(b'\x01\x00')
|
||||
assert_raises(ValueError, format.read_array_header_1_0, s)
|
||||
|
||||
# headers without the exact keys required should fail
|
||||
d = {"shape": (1, 2),
|
||||
"descr": "x"}
|
||||
s = BytesIO()
|
||||
format.write_array_header_1_0(s, d)
|
||||
assert_raises(ValueError, format.read_array_header_1_0, s)
|
||||
|
||||
d = {"shape": (1, 2),
|
||||
"fortran_order": False,
|
||||
"descr": "x",
|
||||
"extrakey": -1}
|
||||
s = BytesIO()
|
||||
format.write_array_header_1_0(s, d)
|
||||
assert_raises(ValueError, format.read_array_header_1_0, s)
|
||||
|
||||
|
||||
def test_large_file_support():
|
||||
if (sys.platform == 'win32' or sys.platform == 'cygwin'):
|
||||
pytest.skip("Unknown if Windows has sparse filesystems")
|
||||
# try creating a large sparse file
|
||||
tf_name = os.path.join(tempdir, 'sparse_file')
|
||||
try:
|
||||
# seek past end would work too, but linux truncate somewhat
|
||||
# increases the chances that we have a sparse filesystem and can
|
||||
# avoid actually writing 5GB
|
||||
import subprocess as sp
|
||||
sp.check_call(["truncate", "-s", "5368709120", tf_name])
|
||||
except Exception:
|
||||
pytest.skip("Could not create 5GB large file")
|
||||
# write a small array to the end
|
||||
with open(tf_name, "wb") as f:
|
||||
f.seek(5368709120)
|
||||
d = np.arange(5)
|
||||
np.save(f, d)
|
||||
# read it back
|
||||
with open(tf_name, "rb") as f:
|
||||
f.seek(5368709120)
|
||||
r = np.load(f)
|
||||
assert_array_equal(r, d)
|
||||
|
||||
|
||||
@pytest.mark.skipif(np.dtype(np.intp).itemsize < 8,
|
||||
reason="test requires 64-bit system")
|
||||
@pytest.mark.slow
|
||||
def test_large_archive():
|
||||
# Regression test for product of saving arrays with dimensions of array
|
||||
# having a product that doesn't fit in int32. See gh-7598 for details.
|
||||
try:
|
||||
a = np.empty((2**30, 2), dtype=np.uint8)
|
||||
except MemoryError:
|
||||
pytest.skip("Could not create large file")
|
||||
|
||||
fname = os.path.join(tempdir, "large_archive")
|
||||
|
||||
with open(fname, "wb") as f:
|
||||
np.savez(f, arr=a)
|
||||
|
||||
with open(fname, "rb") as f:
|
||||
new_a = np.load(f)["arr"]
|
||||
|
||||
assert_(a.shape == new_a.shape)
|
||||
|
||||
|
||||
def test_empty_npz():
|
||||
# Test for gh-9989
|
||||
fname = os.path.join(tempdir, "nothing.npz")
|
||||
np.savez(fname)
|
||||
np.load(fname)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,833 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import numpy as np
|
||||
|
||||
from numpy.lib.histograms import histogram, histogramdd, histogram_bin_edges
|
||||
from numpy.testing import (
|
||||
assert_, assert_equal, assert_array_equal, assert_almost_equal,
|
||||
assert_array_almost_equal, assert_raises, assert_allclose,
|
||||
assert_array_max_ulp, assert_raises_regex, suppress_warnings,
|
||||
)
|
||||
|
||||
|
||||
class TestHistogram(object):
|
||||
|
||||
def setup(self):
|
||||
pass
|
||||
|
||||
def teardown(self):
|
||||
pass
|
||||
|
||||
def test_simple(self):
|
||||
n = 100
|
||||
v = np.random.rand(n)
|
||||
(a, b) = histogram(v)
|
||||
# check if the sum of the bins equals the number of samples
|
||||
assert_equal(np.sum(a, axis=0), n)
|
||||
# check that the bin counts are evenly spaced when the data is from
|
||||
# a linear function
|
||||
(a, b) = histogram(np.linspace(0, 10, 100))
|
||||
assert_array_equal(a, 10)
|
||||
|
||||
def test_one_bin(self):
|
||||
# Ticket 632
|
||||
hist, edges = histogram([1, 2, 3, 4], [1, 2])
|
||||
assert_array_equal(hist, [2, ])
|
||||
assert_array_equal(edges, [1, 2])
|
||||
assert_raises(ValueError, histogram, [1, 2], bins=0)
|
||||
h, e = histogram([1, 2], bins=1)
|
||||
assert_equal(h, np.array([2]))
|
||||
assert_allclose(e, np.array([1., 2.]))
|
||||
|
||||
def test_normed(self):
|
||||
sup = suppress_warnings()
|
||||
with sup:
|
||||
rec = sup.record(np.VisibleDeprecationWarning, '.*normed.*')
|
||||
# Check that the integral of the density equals 1.
|
||||
n = 100
|
||||
v = np.random.rand(n)
|
||||
a, b = histogram(v, normed=True)
|
||||
area = np.sum(a * np.diff(b))
|
||||
assert_almost_equal(area, 1)
|
||||
assert_equal(len(rec), 1)
|
||||
|
||||
sup = suppress_warnings()
|
||||
with sup:
|
||||
rec = sup.record(np.VisibleDeprecationWarning, '.*normed.*')
|
||||
# Check with non-constant bin widths (buggy but backwards
|
||||
# compatible)
|
||||
v = np.arange(10)
|
||||
bins = [0, 1, 5, 9, 10]
|
||||
a, b = histogram(v, bins, normed=True)
|
||||
area = np.sum(a * np.diff(b))
|
||||
assert_almost_equal(area, 1)
|
||||
assert_equal(len(rec), 1)
|
||||
|
||||
def test_density(self):
|
||||
# Check that the integral of the density equals 1.
|
||||
n = 100
|
||||
v = np.random.rand(n)
|
||||
a, b = histogram(v, density=True)
|
||||
area = np.sum(a * np.diff(b))
|
||||
assert_almost_equal(area, 1)
|
||||
|
||||
# Check with non-constant bin widths
|
||||
v = np.arange(10)
|
||||
bins = [0, 1, 3, 6, 10]
|
||||
a, b = histogram(v, bins, density=True)
|
||||
assert_array_equal(a, .1)
|
||||
assert_equal(np.sum(a * np.diff(b)), 1)
|
||||
|
||||
# Test that passing False works too
|
||||
a, b = histogram(v, bins, density=False)
|
||||
assert_array_equal(a, [1, 2, 3, 4])
|
||||
|
||||
# Variale bin widths are especially useful to deal with
|
||||
# infinities.
|
||||
v = np.arange(10)
|
||||
bins = [0, 1, 3, 6, np.inf]
|
||||
a, b = histogram(v, bins, density=True)
|
||||
assert_array_equal(a, [.1, .1, .1, 0.])
|
||||
|
||||
# Taken from a bug report from N. Becker on the numpy-discussion
|
||||
# mailing list Aug. 6, 2010.
|
||||
counts, dmy = np.histogram(
|
||||
[1, 2, 3, 4], [0.5, 1.5, np.inf], density=True)
|
||||
assert_equal(counts, [.25, 0])
|
||||
|
||||
def test_outliers(self):
|
||||
# Check that outliers are not tallied
|
||||
a = np.arange(10) + .5
|
||||
|
||||
# Lower outliers
|
||||
h, b = histogram(a, range=[0, 9])
|
||||
assert_equal(h.sum(), 9)
|
||||
|
||||
# Upper outliers
|
||||
h, b = histogram(a, range=[1, 10])
|
||||
assert_equal(h.sum(), 9)
|
||||
|
||||
# Normalization
|
||||
h, b = histogram(a, range=[1, 9], density=True)
|
||||
assert_almost_equal((h * np.diff(b)).sum(), 1, decimal=15)
|
||||
|
||||
# Weights
|
||||
w = np.arange(10) + .5
|
||||
h, b = histogram(a, range=[1, 9], weights=w, density=True)
|
||||
assert_equal((h * np.diff(b)).sum(), 1)
|
||||
|
||||
h, b = histogram(a, bins=8, range=[1, 9], weights=w)
|
||||
assert_equal(h, w[1:-1])
|
||||
|
||||
def test_arr_weights_mismatch(self):
|
||||
a = np.arange(10) + .5
|
||||
w = np.arange(11) + .5
|
||||
with assert_raises_regex(ValueError, "same shape as"):
|
||||
h, b = histogram(a, range=[1, 9], weights=w, density=True)
|
||||
|
||||
|
||||
def test_type(self):
|
||||
# Check the type of the returned histogram
|
||||
a = np.arange(10) + .5
|
||||
h, b = histogram(a)
|
||||
assert_(np.issubdtype(h.dtype, np.integer))
|
||||
|
||||
h, b = histogram(a, density=True)
|
||||
assert_(np.issubdtype(h.dtype, np.floating))
|
||||
|
||||
h, b = histogram(a, weights=np.ones(10, int))
|
||||
assert_(np.issubdtype(h.dtype, np.integer))
|
||||
|
||||
h, b = histogram(a, weights=np.ones(10, float))
|
||||
assert_(np.issubdtype(h.dtype, np.floating))
|
||||
|
||||
def test_f32_rounding(self):
|
||||
# gh-4799, check that the rounding of the edges works with float32
|
||||
x = np.array([276.318359, -69.593948, 21.329449], dtype=np.float32)
|
||||
y = np.array([5005.689453, 4481.327637, 6010.369629], dtype=np.float32)
|
||||
counts_hist, xedges, yedges = np.histogram2d(x, y, bins=100)
|
||||
assert_equal(counts_hist.sum(), 3.)
|
||||
|
||||
def test_bool_conversion(self):
|
||||
# gh-12107
|
||||
# Reference integer histogram
|
||||
a = np.array([1, 1, 0], dtype=np.uint8)
|
||||
int_hist, int_edges = np.histogram(a)
|
||||
|
||||
# Should raise an warning on booleans
|
||||
# Ensure that the histograms are equivalent, need to suppress
|
||||
# the warnings to get the actual outputs
|
||||
with suppress_warnings() as sup:
|
||||
rec = sup.record(RuntimeWarning, 'Converting input from .*')
|
||||
hist, edges = np.histogram([True, True, False])
|
||||
# A warning should be issued
|
||||
assert_equal(len(rec), 1)
|
||||
assert_array_equal(hist, int_hist)
|
||||
assert_array_equal(edges, int_edges)
|
||||
|
||||
def test_weights(self):
|
||||
v = np.random.rand(100)
|
||||
w = np.ones(100) * 5
|
||||
a, b = histogram(v)
|
||||
na, nb = histogram(v, density=True)
|
||||
wa, wb = histogram(v, weights=w)
|
||||
nwa, nwb = histogram(v, weights=w, density=True)
|
||||
assert_array_almost_equal(a * 5, wa)
|
||||
assert_array_almost_equal(na, nwa)
|
||||
|
||||
# Check weights are properly applied.
|
||||
v = np.linspace(0, 10, 10)
|
||||
w = np.concatenate((np.zeros(5), np.ones(5)))
|
||||
wa, wb = histogram(v, bins=np.arange(11), weights=w)
|
||||
assert_array_almost_equal(wa, w)
|
||||
|
||||
# Check with integer weights
|
||||
wa, wb = histogram([1, 2, 2, 4], bins=4, weights=[4, 3, 2, 1])
|
||||
assert_array_equal(wa, [4, 5, 0, 1])
|
||||
wa, wb = histogram(
|
||||
[1, 2, 2, 4], bins=4, weights=[4, 3, 2, 1], density=True)
|
||||
assert_array_almost_equal(wa, np.array([4, 5, 0, 1]) / 10. / 3. * 4)
|
||||
|
||||
# Check weights with non-uniform bin widths
|
||||
a, b = histogram(
|
||||
np.arange(9), [0, 1, 3, 6, 10],
|
||||
weights=[2, 1, 1, 1, 1, 1, 1, 1, 1], density=True)
|
||||
assert_almost_equal(a, [.2, .1, .1, .075])
|
||||
|
||||
def test_exotic_weights(self):
|
||||
|
||||
# Test the use of weights that are not integer or floats, but e.g.
|
||||
# complex numbers or object types.
|
||||
|
||||
# Complex weights
|
||||
values = np.array([1.3, 2.5, 2.3])
|
||||
weights = np.array([1, -1, 2]) + 1j * np.array([2, 1, 2])
|
||||
|
||||
# Check with custom bins
|
||||
wa, wb = histogram(values, bins=[0, 2, 3], weights=weights)
|
||||
assert_array_almost_equal(wa, np.array([1, 1]) + 1j * np.array([2, 3]))
|
||||
|
||||
# Check with even bins
|
||||
wa, wb = histogram(values, bins=2, range=[1, 3], weights=weights)
|
||||
assert_array_almost_equal(wa, np.array([1, 1]) + 1j * np.array([2, 3]))
|
||||
|
||||
# Decimal weights
|
||||
from decimal import Decimal
|
||||
values = np.array([1.3, 2.5, 2.3])
|
||||
weights = np.array([Decimal(1), Decimal(2), Decimal(3)])
|
||||
|
||||
# Check with custom bins
|
||||
wa, wb = histogram(values, bins=[0, 2, 3], weights=weights)
|
||||
assert_array_almost_equal(wa, [Decimal(1), Decimal(5)])
|
||||
|
||||
# Check with even bins
|
||||
wa, wb = histogram(values, bins=2, range=[1, 3], weights=weights)
|
||||
assert_array_almost_equal(wa, [Decimal(1), Decimal(5)])
|
||||
|
||||
def test_no_side_effects(self):
|
||||
# This is a regression test that ensures that values passed to
|
||||
# ``histogram`` are unchanged.
|
||||
values = np.array([1.3, 2.5, 2.3])
|
||||
np.histogram(values, range=[-10, 10], bins=100)
|
||||
assert_array_almost_equal(values, [1.3, 2.5, 2.3])
|
||||
|
||||
def test_empty(self):
|
||||
a, b = histogram([], bins=([0, 1]))
|
||||
assert_array_equal(a, np.array([0]))
|
||||
assert_array_equal(b, np.array([0, 1]))
|
||||
|
||||
def test_error_binnum_type (self):
|
||||
# Tests if right Error is raised if bins argument is float
|
||||
vals = np.linspace(0.0, 1.0, num=100)
|
||||
histogram(vals, 5)
|
||||
assert_raises(TypeError, histogram, vals, 2.4)
|
||||
|
||||
def test_finite_range(self):
|
||||
# Normal ranges should be fine
|
||||
vals = np.linspace(0.0, 1.0, num=100)
|
||||
histogram(vals, range=[0.25,0.75])
|
||||
assert_raises(ValueError, histogram, vals, range=[np.nan,0.75])
|
||||
assert_raises(ValueError, histogram, vals, range=[0.25,np.inf])
|
||||
|
||||
def test_invalid_range(self):
|
||||
# start of range must be < end of range
|
||||
vals = np.linspace(0.0, 1.0, num=100)
|
||||
with assert_raises_regex(ValueError, "max must be larger than"):
|
||||
np.histogram(vals, range=[0.1, 0.01])
|
||||
|
||||
def test_bin_edge_cases(self):
|
||||
# Ensure that floating-point computations correctly place edge cases.
|
||||
arr = np.array([337, 404, 739, 806, 1007, 1811, 2012])
|
||||
hist, edges = np.histogram(arr, bins=8296, range=(2, 2280))
|
||||
mask = hist > 0
|
||||
left_edges = edges[:-1][mask]
|
||||
right_edges = edges[1:][mask]
|
||||
for x, left, right in zip(arr, left_edges, right_edges):
|
||||
assert_(x >= left)
|
||||
assert_(x < right)
|
||||
|
||||
def test_last_bin_inclusive_range(self):
|
||||
arr = np.array([0., 0., 0., 1., 2., 3., 3., 4., 5.])
|
||||
hist, edges = np.histogram(arr, bins=30, range=(-0.5, 5))
|
||||
assert_equal(hist[-1], 1)
|
||||
|
||||
def test_bin_array_dims(self):
|
||||
# gracefully handle bins object > 1 dimension
|
||||
vals = np.linspace(0.0, 1.0, num=100)
|
||||
bins = np.array([[0, 0.5], [0.6, 1.0]])
|
||||
with assert_raises_regex(ValueError, "must be 1d"):
|
||||
np.histogram(vals, bins=bins)
|
||||
|
||||
def test_unsigned_monotonicity_check(self):
|
||||
# Ensures ValueError is raised if bins not increasing monotonically
|
||||
# when bins contain unsigned values (see #9222)
|
||||
arr = np.array([2])
|
||||
bins = np.array([1, 3, 1], dtype='uint64')
|
||||
with assert_raises(ValueError):
|
||||
hist, edges = np.histogram(arr, bins=bins)
|
||||
|
||||
def test_object_array_of_0d(self):
|
||||
# gh-7864
|
||||
assert_raises(ValueError,
|
||||
histogram, [np.array(0.4) for i in range(10)] + [-np.inf])
|
||||
assert_raises(ValueError,
|
||||
histogram, [np.array(0.4) for i in range(10)] + [np.inf])
|
||||
|
||||
# these should not crash
|
||||
np.histogram([np.array(0.5) for i in range(10)] + [.500000000000001])
|
||||
np.histogram([np.array(0.5) for i in range(10)] + [.5])
|
||||
|
||||
def test_some_nan_values(self):
|
||||
# gh-7503
|
||||
one_nan = np.array([0, 1, np.nan])
|
||||
all_nan = np.array([np.nan, np.nan])
|
||||
|
||||
# the internal comparisons with NaN give warnings
|
||||
sup = suppress_warnings()
|
||||
sup.filter(RuntimeWarning)
|
||||
with sup:
|
||||
# can't infer range with nan
|
||||
assert_raises(ValueError, histogram, one_nan, bins='auto')
|
||||
assert_raises(ValueError, histogram, all_nan, bins='auto')
|
||||
|
||||
# explicit range solves the problem
|
||||
h, b = histogram(one_nan, bins='auto', range=(0, 1))
|
||||
assert_equal(h.sum(), 2) # nan is not counted
|
||||
h, b = histogram(all_nan, bins='auto', range=(0, 1))
|
||||
assert_equal(h.sum(), 0) # nan is not counted
|
||||
|
||||
# as does an explicit set of bins
|
||||
h, b = histogram(one_nan, bins=[0, 1])
|
||||
assert_equal(h.sum(), 2) # nan is not counted
|
||||
h, b = histogram(all_nan, bins=[0, 1])
|
||||
assert_equal(h.sum(), 0) # nan is not counted
|
||||
|
||||
def test_datetime(self):
|
||||
begin = np.datetime64('2000-01-01', 'D')
|
||||
offsets = np.array([0, 0, 1, 1, 2, 3, 5, 10, 20])
|
||||
bins = np.array([0, 2, 7, 20])
|
||||
dates = begin + offsets
|
||||
date_bins = begin + bins
|
||||
|
||||
td = np.dtype('timedelta64[D]')
|
||||
|
||||
# Results should be the same for integer offsets or datetime values.
|
||||
# For now, only explicit bins are supported, since linspace does not
|
||||
# work on datetimes or timedeltas
|
||||
d_count, d_edge = histogram(dates, bins=date_bins)
|
||||
t_count, t_edge = histogram(offsets.astype(td), bins=bins.astype(td))
|
||||
i_count, i_edge = histogram(offsets, bins=bins)
|
||||
|
||||
assert_equal(d_count, i_count)
|
||||
assert_equal(t_count, i_count)
|
||||
|
||||
assert_equal((d_edge - begin).astype(int), i_edge)
|
||||
assert_equal(t_edge.astype(int), i_edge)
|
||||
|
||||
assert_equal(d_edge.dtype, dates.dtype)
|
||||
assert_equal(t_edge.dtype, td)
|
||||
|
||||
def do_signed_overflow_bounds(self, dtype):
|
||||
exponent = 8 * np.dtype(dtype).itemsize - 1
|
||||
arr = np.array([-2**exponent + 4, 2**exponent - 4], dtype=dtype)
|
||||
hist, e = histogram(arr, bins=2)
|
||||
assert_equal(e, [-2**exponent + 4, 0, 2**exponent - 4])
|
||||
assert_equal(hist, [1, 1])
|
||||
|
||||
def test_signed_overflow_bounds(self):
|
||||
self.do_signed_overflow_bounds(np.byte)
|
||||
self.do_signed_overflow_bounds(np.short)
|
||||
self.do_signed_overflow_bounds(np.intc)
|
||||
self.do_signed_overflow_bounds(np.int_)
|
||||
self.do_signed_overflow_bounds(np.longlong)
|
||||
|
||||
def do_precision_lower_bound(self, float_small, float_large):
|
||||
eps = np.finfo(float_large).eps
|
||||
|
||||
arr = np.array([1.0], float_small)
|
||||
range = np.array([1.0 + eps, 2.0], float_large)
|
||||
|
||||
# test is looking for behavior when the bounds change between dtypes
|
||||
if range.astype(float_small)[0] != 1:
|
||||
return
|
||||
|
||||
# previously crashed
|
||||
count, x_loc = np.histogram(arr, bins=1, range=range)
|
||||
assert_equal(count, [1])
|
||||
|
||||
# gh-10322 means that the type comes from arr - this may change
|
||||
assert_equal(x_loc.dtype, float_small)
|
||||
|
||||
def do_precision_upper_bound(self, float_small, float_large):
|
||||
eps = np.finfo(float_large).eps
|
||||
|
||||
arr = np.array([1.0], float_small)
|
||||
range = np.array([0.0, 1.0 - eps], float_large)
|
||||
|
||||
# test is looking for behavior when the bounds change between dtypes
|
||||
if range.astype(float_small)[-1] != 1:
|
||||
return
|
||||
|
||||
# previously crashed
|
||||
count, x_loc = np.histogram(arr, bins=1, range=range)
|
||||
assert_equal(count, [1])
|
||||
|
||||
# gh-10322 means that the type comes from arr - this may change
|
||||
assert_equal(x_loc.dtype, float_small)
|
||||
|
||||
def do_precision(self, float_small, float_large):
|
||||
self.do_precision_lower_bound(float_small, float_large)
|
||||
self.do_precision_upper_bound(float_small, float_large)
|
||||
|
||||
def test_precision(self):
|
||||
# not looping results in a useful stack trace upon failure
|
||||
self.do_precision(np.half, np.single)
|
||||
self.do_precision(np.half, np.double)
|
||||
self.do_precision(np.half, np.longdouble)
|
||||
self.do_precision(np.single, np.double)
|
||||
self.do_precision(np.single, np.longdouble)
|
||||
self.do_precision(np.double, np.longdouble)
|
||||
|
||||
def test_histogram_bin_edges(self):
|
||||
hist, e = histogram([1, 2, 3, 4], [1, 2])
|
||||
edges = histogram_bin_edges([1, 2, 3, 4], [1, 2])
|
||||
assert_array_equal(edges, e)
|
||||
|
||||
arr = np.array([0., 0., 0., 1., 2., 3., 3., 4., 5.])
|
||||
hist, e = histogram(arr, bins=30, range=(-0.5, 5))
|
||||
edges = histogram_bin_edges(arr, bins=30, range=(-0.5, 5))
|
||||
assert_array_equal(edges, e)
|
||||
|
||||
hist, e = histogram(arr, bins='auto', range=(0, 1))
|
||||
edges = histogram_bin_edges(arr, bins='auto', range=(0, 1))
|
||||
assert_array_equal(edges, e)
|
||||
|
||||
|
||||
class TestHistogramOptimBinNums(object):
|
||||
"""
|
||||
Provide test coverage when using provided estimators for optimal number of
|
||||
bins
|
||||
"""
|
||||
|
||||
def test_empty(self):
|
||||
estimator_list = ['fd', 'scott', 'rice', 'sturges',
|
||||
'doane', 'sqrt', 'auto', 'stone']
|
||||
# check it can deal with empty data
|
||||
for estimator in estimator_list:
|
||||
a, b = histogram([], bins=estimator)
|
||||
assert_array_equal(a, np.array([0]))
|
||||
assert_array_equal(b, np.array([0, 1]))
|
||||
|
||||
def test_simple(self):
|
||||
"""
|
||||
Straightforward testing with a mixture of linspace data (for
|
||||
consistency). All test values have been precomputed and the values
|
||||
shouldn't change
|
||||
"""
|
||||
# Some basic sanity checking, with some fixed data.
|
||||
# Checking for the correct number of bins
|
||||
basic_test = {50: {'fd': 4, 'scott': 4, 'rice': 8, 'sturges': 7,
|
||||
'doane': 8, 'sqrt': 8, 'auto': 7, 'stone': 2},
|
||||
500: {'fd': 8, 'scott': 8, 'rice': 16, 'sturges': 10,
|
||||
'doane': 12, 'sqrt': 23, 'auto': 10, 'stone': 9},
|
||||
5000: {'fd': 17, 'scott': 17, 'rice': 35, 'sturges': 14,
|
||||
'doane': 17, 'sqrt': 71, 'auto': 17, 'stone': 20}}
|
||||
|
||||
for testlen, expectedResults in basic_test.items():
|
||||
# Create some sort of non uniform data to test with
|
||||
# (2 peak uniform mixture)
|
||||
x1 = np.linspace(-10, -1, testlen // 5 * 2)
|
||||
x2 = np.linspace(1, 10, testlen // 5 * 3)
|
||||
x = np.concatenate((x1, x2))
|
||||
for estimator, numbins in expectedResults.items():
|
||||
a, b = np.histogram(x, estimator)
|
||||
assert_equal(len(a), numbins, err_msg="For the {0} estimator "
|
||||
"with datasize of {1}".format(estimator, testlen))
|
||||
|
||||
def test_small(self):
|
||||
"""
|
||||
Smaller datasets have the potential to cause issues with the data
|
||||
adaptive methods, especially the FD method. All bin numbers have been
|
||||
precalculated.
|
||||
"""
|
||||
small_dat = {1: {'fd': 1, 'scott': 1, 'rice': 1, 'sturges': 1,
|
||||
'doane': 1, 'sqrt': 1, 'stone': 1},
|
||||
2: {'fd': 2, 'scott': 1, 'rice': 3, 'sturges': 2,
|
||||
'doane': 1, 'sqrt': 2, 'stone': 1},
|
||||
3: {'fd': 2, 'scott': 2, 'rice': 3, 'sturges': 3,
|
||||
'doane': 3, 'sqrt': 2, 'stone': 1}}
|
||||
|
||||
for testlen, expectedResults in small_dat.items():
|
||||
testdat = np.arange(testlen)
|
||||
for estimator, expbins in expectedResults.items():
|
||||
a, b = np.histogram(testdat, estimator)
|
||||
assert_equal(len(a), expbins, err_msg="For the {0} estimator "
|
||||
"with datasize of {1}".format(estimator, testlen))
|
||||
|
||||
def test_incorrect_methods(self):
|
||||
"""
|
||||
Check a Value Error is thrown when an unknown string is passed in
|
||||
"""
|
||||
check_list = ['mad', 'freeman', 'histograms', 'IQR']
|
||||
for estimator in check_list:
|
||||
assert_raises(ValueError, histogram, [1, 2, 3], estimator)
|
||||
|
||||
def test_novariance(self):
|
||||
"""
|
||||
Check that methods handle no variance in data
|
||||
Primarily for Scott and FD as the SD and IQR are both 0 in this case
|
||||
"""
|
||||
novar_dataset = np.ones(100)
|
||||
novar_resultdict = {'fd': 1, 'scott': 1, 'rice': 1, 'sturges': 1,
|
||||
'doane': 1, 'sqrt': 1, 'auto': 1, 'stone': 1}
|
||||
|
||||
for estimator, numbins in novar_resultdict.items():
|
||||
a, b = np.histogram(novar_dataset, estimator)
|
||||
assert_equal(len(a), numbins, err_msg="{0} estimator, "
|
||||
"No Variance test".format(estimator))
|
||||
|
||||
def test_limited_variance(self):
|
||||
"""
|
||||
Check when IQR is 0, but variance exists, we return the sturges value
|
||||
and not the fd value.
|
||||
"""
|
||||
lim_var_data = np.ones(1000)
|
||||
lim_var_data[:3] = 0
|
||||
lim_var_data[-4:] = 100
|
||||
|
||||
edges_auto = histogram_bin_edges(lim_var_data, 'auto')
|
||||
assert_equal(edges_auto, np.linspace(0, 100, 12))
|
||||
|
||||
edges_fd = histogram_bin_edges(lim_var_data, 'fd')
|
||||
assert_equal(edges_fd, np.array([0, 100]))
|
||||
|
||||
edges_sturges = histogram_bin_edges(lim_var_data, 'sturges')
|
||||
assert_equal(edges_sturges, np.linspace(0, 100, 12))
|
||||
|
||||
def test_outlier(self):
|
||||
"""
|
||||
Check the FD, Scott and Doane with outliers.
|
||||
|
||||
The FD estimates a smaller binwidth since it's less affected by
|
||||
outliers. Since the range is so (artificially) large, this means more
|
||||
bins, most of which will be empty, but the data of interest usually is
|
||||
unaffected. The Scott estimator is more affected and returns fewer bins,
|
||||
despite most of the variance being in one area of the data. The Doane
|
||||
estimator lies somewhere between the other two.
|
||||
"""
|
||||
xcenter = np.linspace(-10, 10, 50)
|
||||
outlier_dataset = np.hstack((np.linspace(-110, -100, 5), xcenter))
|
||||
|
||||
outlier_resultdict = {'fd': 21, 'scott': 5, 'doane': 11, 'stone': 6}
|
||||
|
||||
for estimator, numbins in outlier_resultdict.items():
|
||||
a, b = np.histogram(outlier_dataset, estimator)
|
||||
assert_equal(len(a), numbins)
|
||||
|
||||
def test_scott_vs_stone(self):
|
||||
"""Verify that Scott's rule and Stone's rule converges for normally distributed data"""
|
||||
|
||||
def nbins_ratio(seed, size):
|
||||
rng = np.random.RandomState(seed)
|
||||
x = rng.normal(loc=0, scale=2, size=size)
|
||||
a, b = len(np.histogram(x, 'stone')[0]), len(np.histogram(x, 'scott')[0])
|
||||
return a / (a + b)
|
||||
|
||||
ll = [[nbins_ratio(seed, size) for size in np.geomspace(start=10, stop=100, num=4).round().astype(int)]
|
||||
for seed in range(256)]
|
||||
|
||||
# the average difference between the two methods decreases as the dataset size increases.
|
||||
assert_almost_equal(abs(np.mean(ll, axis=0) - 0.5),
|
||||
[0.1065248,
|
||||
0.0968844,
|
||||
0.0331818,
|
||||
0.0178057],
|
||||
decimal=3)
|
||||
|
||||
def test_simple_range(self):
|
||||
"""
|
||||
Straightforward testing with a mixture of linspace data (for
|
||||
consistency). Adding in a 3rd mixture that will then be
|
||||
completely ignored. All test values have been precomputed and
|
||||
the shouldn't change.
|
||||
"""
|
||||
# some basic sanity checking, with some fixed data.
|
||||
# Checking for the correct number of bins
|
||||
basic_test = {
|
||||
50: {'fd': 8, 'scott': 8, 'rice': 15,
|
||||
'sturges': 14, 'auto': 14, 'stone': 8},
|
||||
500: {'fd': 15, 'scott': 16, 'rice': 32,
|
||||
'sturges': 20, 'auto': 20, 'stone': 80},
|
||||
5000: {'fd': 33, 'scott': 33, 'rice': 69,
|
||||
'sturges': 27, 'auto': 33, 'stone': 80}
|
||||
}
|
||||
|
||||
for testlen, expectedResults in basic_test.items():
|
||||
# create some sort of non uniform data to test with
|
||||
# (3 peak uniform mixture)
|
||||
x1 = np.linspace(-10, -1, testlen // 5 * 2)
|
||||
x2 = np.linspace(1, 10, testlen // 5 * 3)
|
||||
x3 = np.linspace(-100, -50, testlen)
|
||||
x = np.hstack((x1, x2, x3))
|
||||
for estimator, numbins in expectedResults.items():
|
||||
a, b = np.histogram(x, estimator, range = (-20, 20))
|
||||
msg = "For the {0} estimator".format(estimator)
|
||||
msg += " with datasize of {0}".format(testlen)
|
||||
assert_equal(len(a), numbins, err_msg=msg)
|
||||
|
||||
def test_simple_weighted(self):
|
||||
"""
|
||||
Check that weighted data raises a TypeError
|
||||
"""
|
||||
estimator_list = ['fd', 'scott', 'rice', 'sturges', 'auto']
|
||||
for estimator in estimator_list:
|
||||
assert_raises(TypeError, histogram, [1, 2, 3],
|
||||
estimator, weights=[1, 2, 3])
|
||||
|
||||
|
||||
class TestHistogramdd(object):
|
||||
|
||||
def test_simple(self):
|
||||
x = np.array([[-.5, .5, 1.5], [-.5, 1.5, 2.5], [-.5, 2.5, .5],
|
||||
[.5, .5, 1.5], [.5, 1.5, 2.5], [.5, 2.5, 2.5]])
|
||||
H, edges = histogramdd(x, (2, 3, 3),
|
||||
range=[[-1, 1], [0, 3], [0, 3]])
|
||||
answer = np.array([[[0, 1, 0], [0, 0, 1], [1, 0, 0]],
|
||||
[[0, 1, 0], [0, 0, 1], [0, 0, 1]]])
|
||||
assert_array_equal(H, answer)
|
||||
|
||||
# Check normalization
|
||||
ed = [[-2, 0, 2], [0, 1, 2, 3], [0, 1, 2, 3]]
|
||||
H, edges = histogramdd(x, bins=ed, density=True)
|
||||
assert_(np.all(H == answer / 12.))
|
||||
|
||||
# Check that H has the correct shape.
|
||||
H, edges = histogramdd(x, (2, 3, 4),
|
||||
range=[[-1, 1], [0, 3], [0, 4]],
|
||||
density=True)
|
||||
answer = np.array([[[0, 1, 0, 0], [0, 0, 1, 0], [1, 0, 0, 0]],
|
||||
[[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 1, 0]]])
|
||||
assert_array_almost_equal(H, answer / 6., 4)
|
||||
# Check that a sequence of arrays is accepted and H has the correct
|
||||
# shape.
|
||||
z = [np.squeeze(y) for y in np.split(x, 3, axis=1)]
|
||||
H, edges = histogramdd(
|
||||
z, bins=(4, 3, 2), range=[[-2, 2], [0, 3], [0, 2]])
|
||||
answer = np.array([[[0, 0], [0, 0], [0, 0]],
|
||||
[[0, 1], [0, 0], [1, 0]],
|
||||
[[0, 1], [0, 0], [0, 0]],
|
||||
[[0, 0], [0, 0], [0, 0]]])
|
||||
assert_array_equal(H, answer)
|
||||
|
||||
Z = np.zeros((5, 5, 5))
|
||||
Z[list(range(5)), list(range(5)), list(range(5))] = 1.
|
||||
H, edges = histogramdd([np.arange(5), np.arange(5), np.arange(5)], 5)
|
||||
assert_array_equal(H, Z)
|
||||
|
||||
def test_shape_3d(self):
|
||||
# All possible permutations for bins of different lengths in 3D.
|
||||
bins = ((5, 4, 6), (6, 4, 5), (5, 6, 4), (4, 6, 5), (6, 5, 4),
|
||||
(4, 5, 6))
|
||||
r = np.random.rand(10, 3)
|
||||
for b in bins:
|
||||
H, edges = histogramdd(r, b)
|
||||
assert_(H.shape == b)
|
||||
|
||||
def test_shape_4d(self):
|
||||
# All possible permutations for bins of different lengths in 4D.
|
||||
bins = ((7, 4, 5, 6), (4, 5, 7, 6), (5, 6, 4, 7), (7, 6, 5, 4),
|
||||
(5, 7, 6, 4), (4, 6, 7, 5), (6, 5, 7, 4), (7, 5, 4, 6),
|
||||
(7, 4, 6, 5), (6, 4, 7, 5), (6, 7, 5, 4), (4, 6, 5, 7),
|
||||
(4, 7, 5, 6), (5, 4, 6, 7), (5, 7, 4, 6), (6, 7, 4, 5),
|
||||
(6, 5, 4, 7), (4, 7, 6, 5), (4, 5, 6, 7), (7, 6, 4, 5),
|
||||
(5, 4, 7, 6), (5, 6, 7, 4), (6, 4, 5, 7), (7, 5, 6, 4))
|
||||
|
||||
r = np.random.rand(10, 4)
|
||||
for b in bins:
|
||||
H, edges = histogramdd(r, b)
|
||||
assert_(H.shape == b)
|
||||
|
||||
def test_weights(self):
|
||||
v = np.random.rand(100, 2)
|
||||
hist, edges = histogramdd(v)
|
||||
n_hist, edges = histogramdd(v, density=True)
|
||||
w_hist, edges = histogramdd(v, weights=np.ones(100))
|
||||
assert_array_equal(w_hist, hist)
|
||||
w_hist, edges = histogramdd(v, weights=np.ones(100) * 2, density=True)
|
||||
assert_array_equal(w_hist, n_hist)
|
||||
w_hist, edges = histogramdd(v, weights=np.ones(100, int) * 2)
|
||||
assert_array_equal(w_hist, 2 * hist)
|
||||
|
||||
def test_identical_samples(self):
|
||||
x = np.zeros((10, 2), int)
|
||||
hist, edges = histogramdd(x, bins=2)
|
||||
assert_array_equal(edges[0], np.array([-0.5, 0., 0.5]))
|
||||
|
||||
def test_empty(self):
|
||||
a, b = histogramdd([[], []], bins=([0, 1], [0, 1]))
|
||||
assert_array_max_ulp(a, np.array([[0.]]))
|
||||
a, b = np.histogramdd([[], [], []], bins=2)
|
||||
assert_array_max_ulp(a, np.zeros((2, 2, 2)))
|
||||
|
||||
def test_bins_errors(self):
|
||||
# There are two ways to specify bins. Check for the right errors
|
||||
# when mixing those.
|
||||
x = np.arange(8).reshape(2, 4)
|
||||
assert_raises(ValueError, np.histogramdd, x, bins=[-1, 2, 4, 5])
|
||||
assert_raises(ValueError, np.histogramdd, x, bins=[1, 0.99, 1, 1])
|
||||
assert_raises(
|
||||
ValueError, np.histogramdd, x, bins=[1, 1, 1, [1, 2, 3, -3]])
|
||||
assert_(np.histogramdd(x, bins=[1, 1, 1, [1, 2, 3, 4]]))
|
||||
|
||||
def test_inf_edges(self):
|
||||
# Test using +/-inf bin edges works. See #1788.
|
||||
with np.errstate(invalid='ignore'):
|
||||
x = np.arange(6).reshape(3, 2)
|
||||
expected = np.array([[1, 0], [0, 1], [0, 1]])
|
||||
h, e = np.histogramdd(x, bins=[3, [-np.inf, 2, 10]])
|
||||
assert_allclose(h, expected)
|
||||
h, e = np.histogramdd(x, bins=[3, np.array([-1, 2, np.inf])])
|
||||
assert_allclose(h, expected)
|
||||
h, e = np.histogramdd(x, bins=[3, [-np.inf, 3, np.inf]])
|
||||
assert_allclose(h, expected)
|
||||
|
||||
def test_rightmost_binedge(self):
|
||||
# Test event very close to rightmost binedge. See Github issue #4266
|
||||
x = [0.9999999995]
|
||||
bins = [[0., 0.5, 1.0]]
|
||||
hist, _ = histogramdd(x, bins=bins)
|
||||
assert_(hist[0] == 0.0)
|
||||
assert_(hist[1] == 1.)
|
||||
x = [1.0]
|
||||
bins = [[0., 0.5, 1.0]]
|
||||
hist, _ = histogramdd(x, bins=bins)
|
||||
assert_(hist[0] == 0.0)
|
||||
assert_(hist[1] == 1.)
|
||||
x = [1.0000000001]
|
||||
bins = [[0., 0.5, 1.0]]
|
||||
hist, _ = histogramdd(x, bins=bins)
|
||||
assert_(hist[0] == 0.0)
|
||||
assert_(hist[1] == 0.0)
|
||||
x = [1.0001]
|
||||
bins = [[0., 0.5, 1.0]]
|
||||
hist, _ = histogramdd(x, bins=bins)
|
||||
assert_(hist[0] == 0.0)
|
||||
assert_(hist[1] == 0.0)
|
||||
|
||||
def test_finite_range(self):
|
||||
vals = np.random.random((100, 3))
|
||||
histogramdd(vals, range=[[0.0, 1.0], [0.25, 0.75], [0.25, 0.5]])
|
||||
assert_raises(ValueError, histogramdd, vals,
|
||||
range=[[0.0, 1.0], [0.25, 0.75], [0.25, np.inf]])
|
||||
assert_raises(ValueError, histogramdd, vals,
|
||||
range=[[0.0, 1.0], [np.nan, 0.75], [0.25, 0.5]])
|
||||
|
||||
def test_equal_edges(self):
|
||||
""" Test that adjacent entries in an edge array can be equal """
|
||||
x = np.array([0, 1, 2])
|
||||
y = np.array([0, 1, 2])
|
||||
x_edges = np.array([0, 2, 2])
|
||||
y_edges = 1
|
||||
hist, edges = histogramdd((x, y), bins=(x_edges, y_edges))
|
||||
|
||||
hist_expected = np.array([
|
||||
[2.],
|
||||
[1.], # x == 2 falls in the final bin
|
||||
])
|
||||
assert_equal(hist, hist_expected)
|
||||
|
||||
def test_edge_dtype(self):
|
||||
""" Test that if an edge array is input, its type is preserved """
|
||||
x = np.array([0, 10, 20])
|
||||
y = x / 10
|
||||
x_edges = np.array([0, 5, 15, 20])
|
||||
y_edges = x_edges / 10
|
||||
hist, edges = histogramdd((x, y), bins=(x_edges, y_edges))
|
||||
|
||||
assert_equal(edges[0].dtype, x_edges.dtype)
|
||||
assert_equal(edges[1].dtype, y_edges.dtype)
|
||||
|
||||
def test_large_integers(self):
|
||||
big = 2**60 # Too large to represent with a full precision float
|
||||
|
||||
x = np.array([0], np.int64)
|
||||
x_edges = np.array([-1, +1], np.int64)
|
||||
y = big + x
|
||||
y_edges = big + x_edges
|
||||
|
||||
hist, edges = histogramdd((x, y), bins=(x_edges, y_edges))
|
||||
|
||||
assert_equal(hist[0, 0], 1)
|
||||
|
||||
def test_density_non_uniform_2d(self):
|
||||
# Defines the following grid:
|
||||
#
|
||||
# 0 2 8
|
||||
# 0+-+-----+
|
||||
# + | +
|
||||
# + | +
|
||||
# 6+-+-----+
|
||||
# 8+-+-----+
|
||||
x_edges = np.array([0, 2, 8])
|
||||
y_edges = np.array([0, 6, 8])
|
||||
relative_areas = np.array([
|
||||
[3, 9],
|
||||
[1, 3]])
|
||||
|
||||
# ensure the number of points in each region is proportional to its area
|
||||
x = np.array([1] + [1]*3 + [7]*3 + [7]*9)
|
||||
y = np.array([7] + [1]*3 + [7]*3 + [1]*9)
|
||||
|
||||
# sanity check that the above worked as intended
|
||||
hist, edges = histogramdd((y, x), bins=(y_edges, x_edges))
|
||||
assert_equal(hist, relative_areas)
|
||||
|
||||
# resulting histogram should be uniform, since counts and areas are propotional
|
||||
hist, edges = histogramdd((y, x), bins=(y_edges, x_edges), density=True)
|
||||
assert_equal(hist, 1 / (8*8))
|
||||
|
||||
def test_density_non_uniform_1d(self):
|
||||
# compare to histogram to show the results are the same
|
||||
v = np.arange(10)
|
||||
bins = np.array([0, 1, 3, 6, 10])
|
||||
hist, edges = histogram(v, bins, density=True)
|
||||
hist_dd, edges_dd = histogramdd((v,), (bins,), density=True)
|
||||
assert_equal(hist, hist_dd)
|
||||
assert_equal(edges, edges_dd[0])
|
||||
|
||||
def test_density_via_normed(self):
|
||||
# normed should simply alias to density argument
|
||||
v = np.arange(10)
|
||||
bins = np.array([0, 1, 3, 6, 10])
|
||||
hist, edges = histogram(v, bins, density=True)
|
||||
hist_dd, edges_dd = histogramdd((v,), (bins,), normed=True)
|
||||
assert_equal(hist, hist_dd)
|
||||
assert_equal(edges, edges_dd[0])
|
||||
|
||||
def test_density_normed_redundancy(self):
|
||||
v = np.arange(10)
|
||||
bins = np.array([0, 1, 3, 6, 10])
|
||||
with assert_raises_regex(TypeError, "Cannot specify both"):
|
||||
hist_dd, edges_dd = histogramdd((v,), (bins,),
|
||||
density=True,
|
||||
normed=True)
|
||||
@@ -0,0 +1,454 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import pytest
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import (
|
||||
assert_, assert_equal, assert_array_equal, assert_almost_equal,
|
||||
assert_array_almost_equal, assert_raises, assert_raises_regex,
|
||||
assert_warns
|
||||
)
|
||||
from numpy.lib.index_tricks import (
|
||||
mgrid, ogrid, ndenumerate, fill_diagonal, diag_indices, diag_indices_from,
|
||||
index_exp, ndindex, r_, s_, ix_
|
||||
)
|
||||
|
||||
|
||||
class TestRavelUnravelIndex(object):
|
||||
def test_basic(self):
|
||||
assert_equal(np.unravel_index(2, (2, 2)), (1, 0))
|
||||
|
||||
# test backwards compatibility with older dims
|
||||
# keyword argument; see Issue #10586
|
||||
with assert_warns(DeprecationWarning):
|
||||
# we should achieve the correct result
|
||||
# AND raise the appropriate warning
|
||||
# when using older "dims" kw argument
|
||||
assert_equal(np.unravel_index(indices=2,
|
||||
dims=(2, 2)),
|
||||
(1, 0))
|
||||
|
||||
# test that new shape argument works properly
|
||||
assert_equal(np.unravel_index(indices=2,
|
||||
shape=(2, 2)),
|
||||
(1, 0))
|
||||
|
||||
# test that an invalid second keyword argument
|
||||
# is properly handled
|
||||
with assert_raises(TypeError):
|
||||
np.unravel_index(indices=2, hape=(2, 2))
|
||||
|
||||
with assert_raises(TypeError):
|
||||
np.unravel_index(2, hape=(2, 2))
|
||||
|
||||
with assert_raises(TypeError):
|
||||
np.unravel_index(254, ims=(17, 94))
|
||||
|
||||
assert_equal(np.ravel_multi_index((1, 0), (2, 2)), 2)
|
||||
assert_equal(np.unravel_index(254, (17, 94)), (2, 66))
|
||||
assert_equal(np.ravel_multi_index((2, 66), (17, 94)), 254)
|
||||
assert_raises(ValueError, np.unravel_index, -1, (2, 2))
|
||||
assert_raises(TypeError, np.unravel_index, 0.5, (2, 2))
|
||||
assert_raises(ValueError, np.unravel_index, 4, (2, 2))
|
||||
assert_raises(ValueError, np.ravel_multi_index, (-3, 1), (2, 2))
|
||||
assert_raises(ValueError, np.ravel_multi_index, (2, 1), (2, 2))
|
||||
assert_raises(ValueError, np.ravel_multi_index, (0, -3), (2, 2))
|
||||
assert_raises(ValueError, np.ravel_multi_index, (0, 2), (2, 2))
|
||||
assert_raises(TypeError, np.ravel_multi_index, (0.1, 0.), (2, 2))
|
||||
|
||||
assert_equal(np.unravel_index((2*3 + 1)*6 + 4, (4, 3, 6)), [2, 1, 4])
|
||||
assert_equal(
|
||||
np.ravel_multi_index([2, 1, 4], (4, 3, 6)), (2*3 + 1)*6 + 4)
|
||||
|
||||
arr = np.array([[3, 6, 6], [4, 5, 1]])
|
||||
assert_equal(np.ravel_multi_index(arr, (7, 6)), [22, 41, 37])
|
||||
assert_equal(
|
||||
np.ravel_multi_index(arr, (7, 6), order='F'), [31, 41, 13])
|
||||
assert_equal(
|
||||
np.ravel_multi_index(arr, (4, 6), mode='clip'), [22, 23, 19])
|
||||
assert_equal(np.ravel_multi_index(arr, (4, 4), mode=('clip', 'wrap')),
|
||||
[12, 13, 13])
|
||||
assert_equal(np.ravel_multi_index((3, 1, 4, 1), (6, 7, 8, 9)), 1621)
|
||||
|
||||
assert_equal(np.unravel_index(np.array([22, 41, 37]), (7, 6)),
|
||||
[[3, 6, 6], [4, 5, 1]])
|
||||
assert_equal(
|
||||
np.unravel_index(np.array([31, 41, 13]), (7, 6), order='F'),
|
||||
[[3, 6, 6], [4, 5, 1]])
|
||||
assert_equal(np.unravel_index(1621, (6, 7, 8, 9)), [3, 1, 4, 1])
|
||||
|
||||
def test_big_indices(self):
|
||||
# ravel_multi_index for big indices (issue #7546)
|
||||
if np.intp == np.int64:
|
||||
arr = ([1, 29], [3, 5], [3, 117], [19, 2],
|
||||
[2379, 1284], [2, 2], [0, 1])
|
||||
assert_equal(
|
||||
np.ravel_multi_index(arr, (41, 7, 120, 36, 2706, 8, 6)),
|
||||
[5627771580, 117259570957])
|
||||
|
||||
# test overflow checking for too big array (issue #7546)
|
||||
dummy_arr = ([0],[0])
|
||||
half_max = np.iinfo(np.intp).max // 2
|
||||
assert_equal(
|
||||
np.ravel_multi_index(dummy_arr, (half_max, 2)), [0])
|
||||
assert_raises(ValueError,
|
||||
np.ravel_multi_index, dummy_arr, (half_max+1, 2))
|
||||
assert_equal(
|
||||
np.ravel_multi_index(dummy_arr, (half_max, 2), order='F'), [0])
|
||||
assert_raises(ValueError,
|
||||
np.ravel_multi_index, dummy_arr, (half_max+1, 2), order='F')
|
||||
|
||||
def test_dtypes(self):
|
||||
# Test with different data types
|
||||
for dtype in [np.int16, np.uint16, np.int32,
|
||||
np.uint32, np.int64, np.uint64]:
|
||||
coords = np.array(
|
||||
[[1, 0, 1, 2, 3, 4], [1, 6, 1, 3, 2, 0]], dtype=dtype)
|
||||
shape = (5, 8)
|
||||
uncoords = 8*coords[0]+coords[1]
|
||||
assert_equal(np.ravel_multi_index(coords, shape), uncoords)
|
||||
assert_equal(coords, np.unravel_index(uncoords, shape))
|
||||
uncoords = coords[0]+5*coords[1]
|
||||
assert_equal(
|
||||
np.ravel_multi_index(coords, shape, order='F'), uncoords)
|
||||
assert_equal(coords, np.unravel_index(uncoords, shape, order='F'))
|
||||
|
||||
coords = np.array(
|
||||
[[1, 0, 1, 2, 3, 4], [1, 6, 1, 3, 2, 0], [1, 3, 1, 0, 9, 5]],
|
||||
dtype=dtype)
|
||||
shape = (5, 8, 10)
|
||||
uncoords = 10*(8*coords[0]+coords[1])+coords[2]
|
||||
assert_equal(np.ravel_multi_index(coords, shape), uncoords)
|
||||
assert_equal(coords, np.unravel_index(uncoords, shape))
|
||||
uncoords = coords[0]+5*(coords[1]+8*coords[2])
|
||||
assert_equal(
|
||||
np.ravel_multi_index(coords, shape, order='F'), uncoords)
|
||||
assert_equal(coords, np.unravel_index(uncoords, shape, order='F'))
|
||||
|
||||
def test_clipmodes(self):
|
||||
# Test clipmodes
|
||||
assert_equal(
|
||||
np.ravel_multi_index([5, 1, -1, 2], (4, 3, 7, 12), mode='wrap'),
|
||||
np.ravel_multi_index([1, 1, 6, 2], (4, 3, 7, 12)))
|
||||
assert_equal(np.ravel_multi_index([5, 1, -1, 2], (4, 3, 7, 12),
|
||||
mode=(
|
||||
'wrap', 'raise', 'clip', 'raise')),
|
||||
np.ravel_multi_index([1, 1, 0, 2], (4, 3, 7, 12)))
|
||||
assert_raises(
|
||||
ValueError, np.ravel_multi_index, [5, 1, -1, 2], (4, 3, 7, 12))
|
||||
|
||||
def test_writeability(self):
|
||||
# See gh-7269
|
||||
x, y = np.unravel_index([1, 2, 3], (4, 5))
|
||||
assert_(x.flags.writeable)
|
||||
assert_(y.flags.writeable)
|
||||
|
||||
def test_0d(self):
|
||||
# gh-580
|
||||
x = np.unravel_index(0, ())
|
||||
assert_equal(x, ())
|
||||
|
||||
assert_raises_regex(ValueError, "0d array", np.unravel_index, [0], ())
|
||||
assert_raises_regex(
|
||||
ValueError, "out of bounds", np.unravel_index, [1], ())
|
||||
|
||||
|
||||
class TestGrid(object):
|
||||
def test_basic(self):
|
||||
a = mgrid[-1:1:10j]
|
||||
b = mgrid[-1:1:0.1]
|
||||
assert_(a.shape == (10,))
|
||||
assert_(b.shape == (20,))
|
||||
assert_(a[0] == -1)
|
||||
assert_almost_equal(a[-1], 1)
|
||||
assert_(b[0] == -1)
|
||||
assert_almost_equal(b[1]-b[0], 0.1, 11)
|
||||
assert_almost_equal(b[-1], b[0]+19*0.1, 11)
|
||||
assert_almost_equal(a[1]-a[0], 2.0/9.0, 11)
|
||||
|
||||
def test_linspace_equivalence(self):
|
||||
y, st = np.linspace(2, 10, retstep=1)
|
||||
assert_almost_equal(st, 8/49.0)
|
||||
assert_array_almost_equal(y, mgrid[2:10:50j], 13)
|
||||
|
||||
def test_nd(self):
|
||||
c = mgrid[-1:1:10j, -2:2:10j]
|
||||
d = mgrid[-1:1:0.1, -2:2:0.2]
|
||||
assert_(c.shape == (2, 10, 10))
|
||||
assert_(d.shape == (2, 20, 20))
|
||||
assert_array_equal(c[0][0, :], -np.ones(10, 'd'))
|
||||
assert_array_equal(c[1][:, 0], -2*np.ones(10, 'd'))
|
||||
assert_array_almost_equal(c[0][-1, :], np.ones(10, 'd'), 11)
|
||||
assert_array_almost_equal(c[1][:, -1], 2*np.ones(10, 'd'), 11)
|
||||
assert_array_almost_equal(d[0, 1, :] - d[0, 0, :],
|
||||
0.1*np.ones(20, 'd'), 11)
|
||||
assert_array_almost_equal(d[1, :, 1] - d[1, :, 0],
|
||||
0.2*np.ones(20, 'd'), 11)
|
||||
|
||||
def test_sparse(self):
|
||||
grid_full = mgrid[-1:1:10j, -2:2:10j]
|
||||
grid_sparse = ogrid[-1:1:10j, -2:2:10j]
|
||||
|
||||
# sparse grids can be made dense by broadcasting
|
||||
grid_broadcast = np.broadcast_arrays(*grid_sparse)
|
||||
for f, b in zip(grid_full, grid_broadcast):
|
||||
assert_equal(f, b)
|
||||
|
||||
@pytest.mark.parametrize("start, stop, step, expected", [
|
||||
(None, 10, 10j, (200, 10)),
|
||||
(-10, 20, None, (1800, 30)),
|
||||
])
|
||||
def test_mgrid_size_none_handling(self, start, stop, step, expected):
|
||||
# regression test None value handling for
|
||||
# start and step values used by mgrid;
|
||||
# internally, this aims to cover previously
|
||||
# unexplored code paths in nd_grid()
|
||||
grid = mgrid[start:stop:step, start:stop:step]
|
||||
# need a smaller grid to explore one of the
|
||||
# untested code paths
|
||||
grid_small = mgrid[start:stop:step]
|
||||
assert_equal(grid.size, expected[0])
|
||||
assert_equal(grid_small.size, expected[1])
|
||||
|
||||
|
||||
class TestConcatenator(object):
|
||||
def test_1d(self):
|
||||
assert_array_equal(r_[1, 2, 3, 4, 5, 6], np.array([1, 2, 3, 4, 5, 6]))
|
||||
b = np.ones(5)
|
||||
c = r_[b, 0, 0, b]
|
||||
assert_array_equal(c, [1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1])
|
||||
|
||||
def test_mixed_type(self):
|
||||
g = r_[10.1, 1:10]
|
||||
assert_(g.dtype == 'f8')
|
||||
|
||||
def test_more_mixed_type(self):
|
||||
g = r_[-10.1, np.array([1]), np.array([2, 3, 4]), 10.0]
|
||||
assert_(g.dtype == 'f8')
|
||||
|
||||
def test_complex_step(self):
|
||||
# Regression test for #12262
|
||||
g = r_[0:36:100j]
|
||||
assert_(g.shape == (100,))
|
||||
|
||||
def test_2d(self):
|
||||
b = np.random.rand(5, 5)
|
||||
c = np.random.rand(5, 5)
|
||||
d = r_['1', b, c] # append columns
|
||||
assert_(d.shape == (5, 10))
|
||||
assert_array_equal(d[:, :5], b)
|
||||
assert_array_equal(d[:, 5:], c)
|
||||
d = r_[b, c]
|
||||
assert_(d.shape == (10, 5))
|
||||
assert_array_equal(d[:5, :], b)
|
||||
assert_array_equal(d[5:, :], c)
|
||||
|
||||
def test_0d(self):
|
||||
assert_equal(r_[0, np.array(1), 2], [0, 1, 2])
|
||||
assert_equal(r_[[0, 1, 2], np.array(3)], [0, 1, 2, 3])
|
||||
assert_equal(r_[np.array(0), [1, 2, 3]], [0, 1, 2, 3])
|
||||
|
||||
|
||||
class TestNdenumerate(object):
|
||||
def test_basic(self):
|
||||
a = np.array([[1, 2], [3, 4]])
|
||||
assert_equal(list(ndenumerate(a)),
|
||||
[((0, 0), 1), ((0, 1), 2), ((1, 0), 3), ((1, 1), 4)])
|
||||
|
||||
|
||||
class TestIndexExpression(object):
|
||||
def test_regression_1(self):
|
||||
# ticket #1196
|
||||
a = np.arange(2)
|
||||
assert_equal(a[:-1], a[s_[:-1]])
|
||||
assert_equal(a[:-1], a[index_exp[:-1]])
|
||||
|
||||
def test_simple_1(self):
|
||||
a = np.random.rand(4, 5, 6)
|
||||
|
||||
assert_equal(a[:, :3, [1, 2]], a[index_exp[:, :3, [1, 2]]])
|
||||
assert_equal(a[:, :3, [1, 2]], a[s_[:, :3, [1, 2]]])
|
||||
|
||||
|
||||
class TestIx_(object):
|
||||
def test_regression_1(self):
|
||||
# Test empty inputs create outputs of indexing type, gh-5804
|
||||
# Test both lists and arrays
|
||||
for func in (range, np.arange):
|
||||
a, = np.ix_(func(0))
|
||||
assert_equal(a.dtype, np.intp)
|
||||
|
||||
def test_shape_and_dtype(self):
|
||||
sizes = (4, 5, 3, 2)
|
||||
# Test both lists and arrays
|
||||
for func in (range, np.arange):
|
||||
arrays = np.ix_(*[func(sz) for sz in sizes])
|
||||
for k, (a, sz) in enumerate(zip(arrays, sizes)):
|
||||
assert_equal(a.shape[k], sz)
|
||||
assert_(all(sh == 1 for j, sh in enumerate(a.shape) if j != k))
|
||||
assert_(np.issubdtype(a.dtype, np.integer))
|
||||
|
||||
def test_bool(self):
|
||||
bool_a = [True, False, True, True]
|
||||
int_a, = np.nonzero(bool_a)
|
||||
assert_equal(np.ix_(bool_a)[0], int_a)
|
||||
|
||||
def test_1d_only(self):
|
||||
idx2d = [[1, 2, 3], [4, 5, 6]]
|
||||
assert_raises(ValueError, np.ix_, idx2d)
|
||||
|
||||
def test_repeated_input(self):
|
||||
length_of_vector = 5
|
||||
x = np.arange(length_of_vector)
|
||||
out = ix_(x, x)
|
||||
assert_equal(out[0].shape, (length_of_vector, 1))
|
||||
assert_equal(out[1].shape, (1, length_of_vector))
|
||||
# check that input shape is not modified
|
||||
assert_equal(x.shape, (length_of_vector,))
|
||||
|
||||
|
||||
def test_c_():
|
||||
a = np.c_[np.array([[1, 2, 3]]), 0, 0, np.array([[4, 5, 6]])]
|
||||
assert_equal(a, [[1, 2, 3, 0, 0, 4, 5, 6]])
|
||||
|
||||
|
||||
class TestFillDiagonal(object):
|
||||
def test_basic(self):
|
||||
a = np.zeros((3, 3), int)
|
||||
fill_diagonal(a, 5)
|
||||
assert_array_equal(
|
||||
a, np.array([[5, 0, 0],
|
||||
[0, 5, 0],
|
||||
[0, 0, 5]])
|
||||
)
|
||||
|
||||
def test_tall_matrix(self):
|
||||
a = np.zeros((10, 3), int)
|
||||
fill_diagonal(a, 5)
|
||||
assert_array_equal(
|
||||
a, np.array([[5, 0, 0],
|
||||
[0, 5, 0],
|
||||
[0, 0, 5],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0]])
|
||||
)
|
||||
|
||||
def test_tall_matrix_wrap(self):
|
||||
a = np.zeros((10, 3), int)
|
||||
fill_diagonal(a, 5, True)
|
||||
assert_array_equal(
|
||||
a, np.array([[5, 0, 0],
|
||||
[0, 5, 0],
|
||||
[0, 0, 5],
|
||||
[0, 0, 0],
|
||||
[5, 0, 0],
|
||||
[0, 5, 0],
|
||||
[0, 0, 5],
|
||||
[0, 0, 0],
|
||||
[5, 0, 0],
|
||||
[0, 5, 0]])
|
||||
)
|
||||
|
||||
def test_wide_matrix(self):
|
||||
a = np.zeros((3, 10), int)
|
||||
fill_diagonal(a, 5)
|
||||
assert_array_equal(
|
||||
a, np.array([[5, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 5, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 5, 0, 0, 0, 0, 0, 0, 0]])
|
||||
)
|
||||
|
||||
def test_operate_4d_array(self):
|
||||
a = np.zeros((3, 3, 3, 3), int)
|
||||
fill_diagonal(a, 4)
|
||||
i = np.array([0, 1, 2])
|
||||
assert_equal(np.where(a != 0), (i, i, i, i))
|
||||
|
||||
def test_low_dim_handling(self):
|
||||
# raise error with low dimensionality
|
||||
a = np.zeros(3, int)
|
||||
with assert_raises_regex(ValueError, "at least 2-d"):
|
||||
fill_diagonal(a, 5)
|
||||
|
||||
def test_hetero_shape_handling(self):
|
||||
# raise error with high dimensionality and
|
||||
# shape mismatch
|
||||
a = np.zeros((3,3,7,3), int)
|
||||
with assert_raises_regex(ValueError, "equal length"):
|
||||
fill_diagonal(a, 2)
|
||||
|
||||
|
||||
def test_diag_indices():
|
||||
di = diag_indices(4)
|
||||
a = np.array([[1, 2, 3, 4],
|
||||
[5, 6, 7, 8],
|
||||
[9, 10, 11, 12],
|
||||
[13, 14, 15, 16]])
|
||||
a[di] = 100
|
||||
assert_array_equal(
|
||||
a, np.array([[100, 2, 3, 4],
|
||||
[5, 100, 7, 8],
|
||||
[9, 10, 100, 12],
|
||||
[13, 14, 15, 100]])
|
||||
)
|
||||
|
||||
# Now, we create indices to manipulate a 3-d array:
|
||||
d3 = diag_indices(2, 3)
|
||||
|
||||
# And use it to set the diagonal of a zeros array to 1:
|
||||
a = np.zeros((2, 2, 2), int)
|
||||
a[d3] = 1
|
||||
assert_array_equal(
|
||||
a, np.array([[[1, 0],
|
||||
[0, 0]],
|
||||
[[0, 0],
|
||||
[0, 1]]])
|
||||
)
|
||||
|
||||
|
||||
class TestDiagIndicesFrom(object):
|
||||
|
||||
def test_diag_indices_from(self):
|
||||
x = np.random.random((4, 4))
|
||||
r, c = diag_indices_from(x)
|
||||
assert_array_equal(r, np.arange(4))
|
||||
assert_array_equal(c, np.arange(4))
|
||||
|
||||
def test_error_small_input(self):
|
||||
x = np.ones(7)
|
||||
with assert_raises_regex(ValueError, "at least 2-d"):
|
||||
diag_indices_from(x)
|
||||
|
||||
def test_error_shape_mismatch(self):
|
||||
x = np.zeros((3, 3, 2, 3), int)
|
||||
with assert_raises_regex(ValueError, "equal length"):
|
||||
diag_indices_from(x)
|
||||
|
||||
|
||||
def test_ndindex():
|
||||
x = list(ndindex(1, 2, 3))
|
||||
expected = [ix for ix, e in ndenumerate(np.zeros((1, 2, 3)))]
|
||||
assert_array_equal(x, expected)
|
||||
|
||||
x = list(ndindex((1, 2, 3)))
|
||||
assert_array_equal(x, expected)
|
||||
|
||||
# Test use of scalars and tuples
|
||||
x = list(ndindex((3,)))
|
||||
assert_array_equal(x, list(ndindex(3)))
|
||||
|
||||
# Make sure size argument is optional
|
||||
x = list(ndindex())
|
||||
assert_equal(x, [()])
|
||||
|
||||
x = list(ndindex(()))
|
||||
assert_equal(x, [()])
|
||||
|
||||
# Make sure 0-sized ndindex works correctly
|
||||
x = list(ndindex(*[0]))
|
||||
assert_equal(x, [])
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,224 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import numbers
|
||||
import operator
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import assert_, assert_equal, assert_raises
|
||||
|
||||
|
||||
PY2 = sys.version_info.major < 3
|
||||
|
||||
|
||||
# NOTE: This class should be kept as an exact copy of the example from the
|
||||
# docstring for NDArrayOperatorsMixin.
|
||||
|
||||
class ArrayLike(np.lib.mixins.NDArrayOperatorsMixin):
|
||||
def __init__(self, value):
|
||||
self.value = np.asarray(value)
|
||||
|
||||
# One might also consider adding the built-in list type to this
|
||||
# list, to support operations like np.add(array_like, list)
|
||||
_HANDLED_TYPES = (np.ndarray, numbers.Number)
|
||||
|
||||
def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
|
||||
out = kwargs.get('out', ())
|
||||
for x in inputs + out:
|
||||
# Only support operations with instances of _HANDLED_TYPES.
|
||||
# Use ArrayLike instead of type(self) for isinstance to
|
||||
# allow subclasses that don't override __array_ufunc__ to
|
||||
# handle ArrayLike objects.
|
||||
if not isinstance(x, self._HANDLED_TYPES + (ArrayLike,)):
|
||||
return NotImplemented
|
||||
|
||||
# Defer to the implementation of the ufunc on unwrapped values.
|
||||
inputs = tuple(x.value if isinstance(x, ArrayLike) else x
|
||||
for x in inputs)
|
||||
if out:
|
||||
kwargs['out'] = tuple(
|
||||
x.value if isinstance(x, ArrayLike) else x
|
||||
for x in out)
|
||||
result = getattr(ufunc, method)(*inputs, **kwargs)
|
||||
|
||||
if type(result) is tuple:
|
||||
# multiple return values
|
||||
return tuple(type(self)(x) for x in result)
|
||||
elif method == 'at':
|
||||
# no return value
|
||||
return None
|
||||
else:
|
||||
# one return value
|
||||
return type(self)(result)
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r)' % (type(self).__name__, self.value)
|
||||
|
||||
|
||||
def wrap_array_like(result):
|
||||
if type(result) is tuple:
|
||||
return tuple(ArrayLike(r) for r in result)
|
||||
else:
|
||||
return ArrayLike(result)
|
||||
|
||||
|
||||
def _assert_equal_type_and_value(result, expected, err_msg=None):
|
||||
assert_equal(type(result), type(expected), err_msg=err_msg)
|
||||
if isinstance(result, tuple):
|
||||
assert_equal(len(result), len(expected), err_msg=err_msg)
|
||||
for result_item, expected_item in zip(result, expected):
|
||||
_assert_equal_type_and_value(result_item, expected_item, err_msg)
|
||||
else:
|
||||
assert_equal(result.value, expected.value, err_msg=err_msg)
|
||||
assert_equal(getattr(result.value, 'dtype', None),
|
||||
getattr(expected.value, 'dtype', None), err_msg=err_msg)
|
||||
|
||||
|
||||
_ALL_BINARY_OPERATORS = [
|
||||
operator.lt,
|
||||
operator.le,
|
||||
operator.eq,
|
||||
operator.ne,
|
||||
operator.gt,
|
||||
operator.ge,
|
||||
operator.add,
|
||||
operator.sub,
|
||||
operator.mul,
|
||||
operator.truediv,
|
||||
operator.floordiv,
|
||||
# TODO: test div on Python 2, only
|
||||
operator.mod,
|
||||
divmod,
|
||||
pow,
|
||||
operator.lshift,
|
||||
operator.rshift,
|
||||
operator.and_,
|
||||
operator.xor,
|
||||
operator.or_,
|
||||
]
|
||||
|
||||
|
||||
class TestNDArrayOperatorsMixin(object):
|
||||
|
||||
def test_array_like_add(self):
|
||||
|
||||
def check(result):
|
||||
_assert_equal_type_and_value(result, ArrayLike(0))
|
||||
|
||||
check(ArrayLike(0) + 0)
|
||||
check(0 + ArrayLike(0))
|
||||
|
||||
check(ArrayLike(0) + np.array(0))
|
||||
check(np.array(0) + ArrayLike(0))
|
||||
|
||||
check(ArrayLike(np.array(0)) + 0)
|
||||
check(0 + ArrayLike(np.array(0)))
|
||||
|
||||
check(ArrayLike(np.array(0)) + np.array(0))
|
||||
check(np.array(0) + ArrayLike(np.array(0)))
|
||||
|
||||
def test_inplace(self):
|
||||
array_like = ArrayLike(np.array([0]))
|
||||
array_like += 1
|
||||
_assert_equal_type_and_value(array_like, ArrayLike(np.array([1])))
|
||||
|
||||
array = np.array([0])
|
||||
array += ArrayLike(1)
|
||||
_assert_equal_type_and_value(array, ArrayLike(np.array([1])))
|
||||
|
||||
def test_opt_out(self):
|
||||
|
||||
class OptOut(object):
|
||||
"""Object that opts out of __array_ufunc__."""
|
||||
__array_ufunc__ = None
|
||||
|
||||
def __add__(self, other):
|
||||
return self
|
||||
|
||||
def __radd__(self, other):
|
||||
return self
|
||||
|
||||
array_like = ArrayLike(1)
|
||||
opt_out = OptOut()
|
||||
|
||||
# supported operations
|
||||
assert_(array_like + opt_out is opt_out)
|
||||
assert_(opt_out + array_like is opt_out)
|
||||
|
||||
# not supported
|
||||
with assert_raises(TypeError):
|
||||
# don't use the Python default, array_like = array_like + opt_out
|
||||
array_like += opt_out
|
||||
with assert_raises(TypeError):
|
||||
array_like - opt_out
|
||||
with assert_raises(TypeError):
|
||||
opt_out - array_like
|
||||
|
||||
def test_subclass(self):
|
||||
|
||||
class SubArrayLike(ArrayLike):
|
||||
"""Should take precedence over ArrayLike."""
|
||||
|
||||
x = ArrayLike(0)
|
||||
y = SubArrayLike(1)
|
||||
_assert_equal_type_and_value(x + y, y)
|
||||
_assert_equal_type_and_value(y + x, y)
|
||||
|
||||
def test_object(self):
|
||||
x = ArrayLike(0)
|
||||
obj = object()
|
||||
with assert_raises(TypeError):
|
||||
x + obj
|
||||
with assert_raises(TypeError):
|
||||
obj + x
|
||||
with assert_raises(TypeError):
|
||||
x += obj
|
||||
|
||||
def test_unary_methods(self):
|
||||
array = np.array([-1, 0, 1, 2])
|
||||
array_like = ArrayLike(array)
|
||||
for op in [operator.neg,
|
||||
operator.pos,
|
||||
abs,
|
||||
operator.invert]:
|
||||
_assert_equal_type_and_value(op(array_like), ArrayLike(op(array)))
|
||||
|
||||
def test_forward_binary_methods(self):
|
||||
array = np.array([-1, 0, 1, 2])
|
||||
array_like = ArrayLike(array)
|
||||
for op in _ALL_BINARY_OPERATORS:
|
||||
expected = wrap_array_like(op(array, 1))
|
||||
actual = op(array_like, 1)
|
||||
err_msg = 'failed for operator {}'.format(op)
|
||||
_assert_equal_type_and_value(expected, actual, err_msg=err_msg)
|
||||
|
||||
def test_reflected_binary_methods(self):
|
||||
for op in _ALL_BINARY_OPERATORS:
|
||||
expected = wrap_array_like(op(2, 1))
|
||||
actual = op(2, ArrayLike(1))
|
||||
err_msg = 'failed for operator {}'.format(op)
|
||||
_assert_equal_type_and_value(expected, actual, err_msg=err_msg)
|
||||
|
||||
def test_matmul(self):
|
||||
array = np.array([1, 2], dtype=np.float64)
|
||||
array_like = ArrayLike(array)
|
||||
expected = ArrayLike(np.float64(5))
|
||||
_assert_equal_type_and_value(expected, np.matmul(array_like, array))
|
||||
if not PY2:
|
||||
_assert_equal_type_and_value(
|
||||
expected, operator.matmul(array_like, array))
|
||||
_assert_equal_type_and_value(
|
||||
expected, operator.matmul(array, array_like))
|
||||
|
||||
def test_ufunc_at(self):
|
||||
array = ArrayLike(np.array([1, 2, 3, 4]))
|
||||
assert_(np.negative.at(array, np.array([0, 1])) is None)
|
||||
_assert_equal_type_and_value(array, ArrayLike([-1, -2, 3, 4]))
|
||||
|
||||
def test_ufunc_two_outputs(self):
|
||||
mantissa, exponent = np.frexp(2 ** -3)
|
||||
expected = (ArrayLike(mantissa), ArrayLike(exponent))
|
||||
_assert_equal_type_and_value(
|
||||
np.frexp(ArrayLike(2 ** -3)), expected)
|
||||
_assert_equal_type_and_value(
|
||||
np.frexp(ArrayLike(np.array(2 ** -3))), expected)
|
||||
@@ -0,0 +1,927 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import warnings
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import (
|
||||
assert_, assert_equal, assert_almost_equal, assert_no_warnings,
|
||||
assert_raises, assert_array_equal, suppress_warnings
|
||||
)
|
||||
|
||||
|
||||
# Test data
|
||||
_ndat = np.array([[0.6244, np.nan, 0.2692, 0.0116, np.nan, 0.1170],
|
||||
[0.5351, -0.9403, np.nan, 0.2100, 0.4759, 0.2833],
|
||||
[np.nan, np.nan, np.nan, 0.1042, np.nan, -0.5954],
|
||||
[0.1610, np.nan, np.nan, 0.1859, 0.3146, np.nan]])
|
||||
|
||||
|
||||
# Rows of _ndat with nans removed
|
||||
_rdat = [np.array([0.6244, 0.2692, 0.0116, 0.1170]),
|
||||
np.array([0.5351, -0.9403, 0.2100, 0.4759, 0.2833]),
|
||||
np.array([0.1042, -0.5954]),
|
||||
np.array([0.1610, 0.1859, 0.3146])]
|
||||
|
||||
# Rows of _ndat with nans converted to ones
|
||||
_ndat_ones = np.array([[0.6244, 1.0, 0.2692, 0.0116, 1.0, 0.1170],
|
||||
[0.5351, -0.9403, 1.0, 0.2100, 0.4759, 0.2833],
|
||||
[1.0, 1.0, 1.0, 0.1042, 1.0, -0.5954],
|
||||
[0.1610, 1.0, 1.0, 0.1859, 0.3146, 1.0]])
|
||||
|
||||
# Rows of _ndat with nans converted to zeros
|
||||
_ndat_zeros = np.array([[0.6244, 0.0, 0.2692, 0.0116, 0.0, 0.1170],
|
||||
[0.5351, -0.9403, 0.0, 0.2100, 0.4759, 0.2833],
|
||||
[0.0, 0.0, 0.0, 0.1042, 0.0, -0.5954],
|
||||
[0.1610, 0.0, 0.0, 0.1859, 0.3146, 0.0]])
|
||||
|
||||
|
||||
class TestNanFunctions_MinMax(object):
|
||||
|
||||
nanfuncs = [np.nanmin, np.nanmax]
|
||||
stdfuncs = [np.min, np.max]
|
||||
|
||||
def test_mutation(self):
|
||||
# Check that passed array is not modified.
|
||||
ndat = _ndat.copy()
|
||||
for f in self.nanfuncs:
|
||||
f(ndat)
|
||||
assert_equal(ndat, _ndat)
|
||||
|
||||
def test_keepdims(self):
|
||||
mat = np.eye(3)
|
||||
for nf, rf in zip(self.nanfuncs, self.stdfuncs):
|
||||
for axis in [None, 0, 1]:
|
||||
tgt = rf(mat, axis=axis, keepdims=True)
|
||||
res = nf(mat, axis=axis, keepdims=True)
|
||||
assert_(res.ndim == tgt.ndim)
|
||||
|
||||
def test_out(self):
|
||||
mat = np.eye(3)
|
||||
for nf, rf in zip(self.nanfuncs, self.stdfuncs):
|
||||
resout = np.zeros(3)
|
||||
tgt = rf(mat, axis=1)
|
||||
res = nf(mat, axis=1, out=resout)
|
||||
assert_almost_equal(res, resout)
|
||||
assert_almost_equal(res, tgt)
|
||||
|
||||
def test_dtype_from_input(self):
|
||||
codes = 'efdgFDG'
|
||||
for nf, rf in zip(self.nanfuncs, self.stdfuncs):
|
||||
for c in codes:
|
||||
mat = np.eye(3, dtype=c)
|
||||
tgt = rf(mat, axis=1).dtype.type
|
||||
res = nf(mat, axis=1).dtype.type
|
||||
assert_(res is tgt)
|
||||
# scalar case
|
||||
tgt = rf(mat, axis=None).dtype.type
|
||||
res = nf(mat, axis=None).dtype.type
|
||||
assert_(res is tgt)
|
||||
|
||||
def test_result_values(self):
|
||||
for nf, rf in zip(self.nanfuncs, self.stdfuncs):
|
||||
tgt = [rf(d) for d in _rdat]
|
||||
res = nf(_ndat, axis=1)
|
||||
assert_almost_equal(res, tgt)
|
||||
|
||||
def test_allnans(self):
|
||||
mat = np.array([np.nan]*9).reshape(3, 3)
|
||||
for f in self.nanfuncs:
|
||||
for axis in [None, 0, 1]:
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
assert_(np.isnan(f(mat, axis=axis)).all())
|
||||
assert_(len(w) == 1, 'no warning raised')
|
||||
assert_(issubclass(w[0].category, RuntimeWarning))
|
||||
# Check scalars
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
assert_(np.isnan(f(np.nan)))
|
||||
assert_(len(w) == 1, 'no warning raised')
|
||||
assert_(issubclass(w[0].category, RuntimeWarning))
|
||||
|
||||
def test_masked(self):
|
||||
mat = np.ma.fix_invalid(_ndat)
|
||||
msk = mat._mask.copy()
|
||||
for f in [np.nanmin]:
|
||||
res = f(mat, axis=1)
|
||||
tgt = f(_ndat, axis=1)
|
||||
assert_equal(res, tgt)
|
||||
assert_equal(mat._mask, msk)
|
||||
assert_(not np.isinf(mat).any())
|
||||
|
||||
def test_scalar(self):
|
||||
for f in self.nanfuncs:
|
||||
assert_(f(0.) == 0.)
|
||||
|
||||
def test_subclass(self):
|
||||
class MyNDArray(np.ndarray):
|
||||
pass
|
||||
|
||||
# Check that it works and that type and
|
||||
# shape are preserved
|
||||
mine = np.eye(3).view(MyNDArray)
|
||||
for f in self.nanfuncs:
|
||||
res = f(mine, axis=0)
|
||||
assert_(isinstance(res, MyNDArray))
|
||||
assert_(res.shape == (3,))
|
||||
res = f(mine, axis=1)
|
||||
assert_(isinstance(res, MyNDArray))
|
||||
assert_(res.shape == (3,))
|
||||
res = f(mine)
|
||||
assert_(res.shape == ())
|
||||
|
||||
# check that rows of nan are dealt with for subclasses (#4628)
|
||||
mine[1] = np.nan
|
||||
for f in self.nanfuncs:
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
res = f(mine, axis=0)
|
||||
assert_(isinstance(res, MyNDArray))
|
||||
assert_(not np.any(np.isnan(res)))
|
||||
assert_(len(w) == 0)
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
res = f(mine, axis=1)
|
||||
assert_(isinstance(res, MyNDArray))
|
||||
assert_(np.isnan(res[1]) and not np.isnan(res[0])
|
||||
and not np.isnan(res[2]))
|
||||
assert_(len(w) == 1, 'no warning raised')
|
||||
assert_(issubclass(w[0].category, RuntimeWarning))
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
res = f(mine)
|
||||
assert_(res.shape == ())
|
||||
assert_(res != np.nan)
|
||||
assert_(len(w) == 0)
|
||||
|
||||
def test_object_array(self):
|
||||
arr = np.array([[1.0, 2.0], [np.nan, 4.0], [np.nan, np.nan]], dtype=object)
|
||||
assert_equal(np.nanmin(arr), 1.0)
|
||||
assert_equal(np.nanmin(arr, axis=0), [1.0, 2.0])
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
# assert_equal does not work on object arrays of nan
|
||||
assert_equal(list(np.nanmin(arr, axis=1)), [1.0, 4.0, np.nan])
|
||||
assert_(len(w) == 1, 'no warning raised')
|
||||
assert_(issubclass(w[0].category, RuntimeWarning))
|
||||
|
||||
|
||||
class TestNanFunctions_ArgminArgmax(object):
|
||||
|
||||
nanfuncs = [np.nanargmin, np.nanargmax]
|
||||
|
||||
def test_mutation(self):
|
||||
# Check that passed array is not modified.
|
||||
ndat = _ndat.copy()
|
||||
for f in self.nanfuncs:
|
||||
f(ndat)
|
||||
assert_equal(ndat, _ndat)
|
||||
|
||||
def test_result_values(self):
|
||||
for f, fcmp in zip(self.nanfuncs, [np.greater, np.less]):
|
||||
for row in _ndat:
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(RuntimeWarning, "invalid value encountered in")
|
||||
ind = f(row)
|
||||
val = row[ind]
|
||||
# comparing with NaN is tricky as the result
|
||||
# is always false except for NaN != NaN
|
||||
assert_(not np.isnan(val))
|
||||
assert_(not fcmp(val, row).any())
|
||||
assert_(not np.equal(val, row[:ind]).any())
|
||||
|
||||
def test_allnans(self):
|
||||
mat = np.array([np.nan]*9).reshape(3, 3)
|
||||
for f in self.nanfuncs:
|
||||
for axis in [None, 0, 1]:
|
||||
assert_raises(ValueError, f, mat, axis=axis)
|
||||
assert_raises(ValueError, f, np.nan)
|
||||
|
||||
def test_empty(self):
|
||||
mat = np.zeros((0, 3))
|
||||
for f in self.nanfuncs:
|
||||
for axis in [0, None]:
|
||||
assert_raises(ValueError, f, mat, axis=axis)
|
||||
for axis in [1]:
|
||||
res = f(mat, axis=axis)
|
||||
assert_equal(res, np.zeros(0))
|
||||
|
||||
def test_scalar(self):
|
||||
for f in self.nanfuncs:
|
||||
assert_(f(0.) == 0.)
|
||||
|
||||
def test_subclass(self):
|
||||
class MyNDArray(np.ndarray):
|
||||
pass
|
||||
|
||||
# Check that it works and that type and
|
||||
# shape are preserved
|
||||
mine = np.eye(3).view(MyNDArray)
|
||||
for f in self.nanfuncs:
|
||||
res = f(mine, axis=0)
|
||||
assert_(isinstance(res, MyNDArray))
|
||||
assert_(res.shape == (3,))
|
||||
res = f(mine, axis=1)
|
||||
assert_(isinstance(res, MyNDArray))
|
||||
assert_(res.shape == (3,))
|
||||
res = f(mine)
|
||||
assert_(res.shape == ())
|
||||
|
||||
|
||||
class TestNanFunctions_IntTypes(object):
|
||||
|
||||
int_types = (np.int8, np.int16, np.int32, np.int64, np.uint8,
|
||||
np.uint16, np.uint32, np.uint64)
|
||||
|
||||
mat = np.array([127, 39, 93, 87, 46])
|
||||
|
||||
def integer_arrays(self):
|
||||
for dtype in self.int_types:
|
||||
yield self.mat.astype(dtype)
|
||||
|
||||
def test_nanmin(self):
|
||||
tgt = np.min(self.mat)
|
||||
for mat in self.integer_arrays():
|
||||
assert_equal(np.nanmin(mat), tgt)
|
||||
|
||||
def test_nanmax(self):
|
||||
tgt = np.max(self.mat)
|
||||
for mat in self.integer_arrays():
|
||||
assert_equal(np.nanmax(mat), tgt)
|
||||
|
||||
def test_nanargmin(self):
|
||||
tgt = np.argmin(self.mat)
|
||||
for mat in self.integer_arrays():
|
||||
assert_equal(np.nanargmin(mat), tgt)
|
||||
|
||||
def test_nanargmax(self):
|
||||
tgt = np.argmax(self.mat)
|
||||
for mat in self.integer_arrays():
|
||||
assert_equal(np.nanargmax(mat), tgt)
|
||||
|
||||
def test_nansum(self):
|
||||
tgt = np.sum(self.mat)
|
||||
for mat in self.integer_arrays():
|
||||
assert_equal(np.nansum(mat), tgt)
|
||||
|
||||
def test_nanprod(self):
|
||||
tgt = np.prod(self.mat)
|
||||
for mat in self.integer_arrays():
|
||||
assert_equal(np.nanprod(mat), tgt)
|
||||
|
||||
def test_nancumsum(self):
|
||||
tgt = np.cumsum(self.mat)
|
||||
for mat in self.integer_arrays():
|
||||
assert_equal(np.nancumsum(mat), tgt)
|
||||
|
||||
def test_nancumprod(self):
|
||||
tgt = np.cumprod(self.mat)
|
||||
for mat in self.integer_arrays():
|
||||
assert_equal(np.nancumprod(mat), tgt)
|
||||
|
||||
def test_nanmean(self):
|
||||
tgt = np.mean(self.mat)
|
||||
for mat in self.integer_arrays():
|
||||
assert_equal(np.nanmean(mat), tgt)
|
||||
|
||||
def test_nanvar(self):
|
||||
tgt = np.var(self.mat)
|
||||
for mat in self.integer_arrays():
|
||||
assert_equal(np.nanvar(mat), tgt)
|
||||
|
||||
tgt = np.var(mat, ddof=1)
|
||||
for mat in self.integer_arrays():
|
||||
assert_equal(np.nanvar(mat, ddof=1), tgt)
|
||||
|
||||
def test_nanstd(self):
|
||||
tgt = np.std(self.mat)
|
||||
for mat in self.integer_arrays():
|
||||
assert_equal(np.nanstd(mat), tgt)
|
||||
|
||||
tgt = np.std(self.mat, ddof=1)
|
||||
for mat in self.integer_arrays():
|
||||
assert_equal(np.nanstd(mat, ddof=1), tgt)
|
||||
|
||||
|
||||
class SharedNanFunctionsTestsMixin(object):
|
||||
def test_mutation(self):
|
||||
# Check that passed array is not modified.
|
||||
ndat = _ndat.copy()
|
||||
for f in self.nanfuncs:
|
||||
f(ndat)
|
||||
assert_equal(ndat, _ndat)
|
||||
|
||||
def test_keepdims(self):
|
||||
mat = np.eye(3)
|
||||
for nf, rf in zip(self.nanfuncs, self.stdfuncs):
|
||||
for axis in [None, 0, 1]:
|
||||
tgt = rf(mat, axis=axis, keepdims=True)
|
||||
res = nf(mat, axis=axis, keepdims=True)
|
||||
assert_(res.ndim == tgt.ndim)
|
||||
|
||||
def test_out(self):
|
||||
mat = np.eye(3)
|
||||
for nf, rf in zip(self.nanfuncs, self.stdfuncs):
|
||||
resout = np.zeros(3)
|
||||
tgt = rf(mat, axis=1)
|
||||
res = nf(mat, axis=1, out=resout)
|
||||
assert_almost_equal(res, resout)
|
||||
assert_almost_equal(res, tgt)
|
||||
|
||||
def test_dtype_from_dtype(self):
|
||||
mat = np.eye(3)
|
||||
codes = 'efdgFDG'
|
||||
for nf, rf in zip(self.nanfuncs, self.stdfuncs):
|
||||
for c in codes:
|
||||
with suppress_warnings() as sup:
|
||||
if nf in {np.nanstd, np.nanvar} and c in 'FDG':
|
||||
# Giving the warning is a small bug, see gh-8000
|
||||
sup.filter(np.ComplexWarning)
|
||||
tgt = rf(mat, dtype=np.dtype(c), axis=1).dtype.type
|
||||
res = nf(mat, dtype=np.dtype(c), axis=1).dtype.type
|
||||
assert_(res is tgt)
|
||||
# scalar case
|
||||
tgt = rf(mat, dtype=np.dtype(c), axis=None).dtype.type
|
||||
res = nf(mat, dtype=np.dtype(c), axis=None).dtype.type
|
||||
assert_(res is tgt)
|
||||
|
||||
def test_dtype_from_char(self):
|
||||
mat = np.eye(3)
|
||||
codes = 'efdgFDG'
|
||||
for nf, rf in zip(self.nanfuncs, self.stdfuncs):
|
||||
for c in codes:
|
||||
with suppress_warnings() as sup:
|
||||
if nf in {np.nanstd, np.nanvar} and c in 'FDG':
|
||||
# Giving the warning is a small bug, see gh-8000
|
||||
sup.filter(np.ComplexWarning)
|
||||
tgt = rf(mat, dtype=c, axis=1).dtype.type
|
||||
res = nf(mat, dtype=c, axis=1).dtype.type
|
||||
assert_(res is tgt)
|
||||
# scalar case
|
||||
tgt = rf(mat, dtype=c, axis=None).dtype.type
|
||||
res = nf(mat, dtype=c, axis=None).dtype.type
|
||||
assert_(res is tgt)
|
||||
|
||||
def test_dtype_from_input(self):
|
||||
codes = 'efdgFDG'
|
||||
for nf, rf in zip(self.nanfuncs, self.stdfuncs):
|
||||
for c in codes:
|
||||
mat = np.eye(3, dtype=c)
|
||||
tgt = rf(mat, axis=1).dtype.type
|
||||
res = nf(mat, axis=1).dtype.type
|
||||
assert_(res is tgt, "res %s, tgt %s" % (res, tgt))
|
||||
# scalar case
|
||||
tgt = rf(mat, axis=None).dtype.type
|
||||
res = nf(mat, axis=None).dtype.type
|
||||
assert_(res is tgt)
|
||||
|
||||
def test_result_values(self):
|
||||
for nf, rf in zip(self.nanfuncs, self.stdfuncs):
|
||||
tgt = [rf(d) for d in _rdat]
|
||||
res = nf(_ndat, axis=1)
|
||||
assert_almost_equal(res, tgt)
|
||||
|
||||
def test_scalar(self):
|
||||
for f in self.nanfuncs:
|
||||
assert_(f(0.) == 0.)
|
||||
|
||||
def test_subclass(self):
|
||||
class MyNDArray(np.ndarray):
|
||||
pass
|
||||
|
||||
# Check that it works and that type and
|
||||
# shape are preserved
|
||||
array = np.eye(3)
|
||||
mine = array.view(MyNDArray)
|
||||
for f in self.nanfuncs:
|
||||
expected_shape = f(array, axis=0).shape
|
||||
res = f(mine, axis=0)
|
||||
assert_(isinstance(res, MyNDArray))
|
||||
assert_(res.shape == expected_shape)
|
||||
expected_shape = f(array, axis=1).shape
|
||||
res = f(mine, axis=1)
|
||||
assert_(isinstance(res, MyNDArray))
|
||||
assert_(res.shape == expected_shape)
|
||||
expected_shape = f(array).shape
|
||||
res = f(mine)
|
||||
assert_(isinstance(res, MyNDArray))
|
||||
assert_(res.shape == expected_shape)
|
||||
|
||||
|
||||
class TestNanFunctions_SumProd(SharedNanFunctionsTestsMixin):
|
||||
|
||||
nanfuncs = [np.nansum, np.nanprod]
|
||||
stdfuncs = [np.sum, np.prod]
|
||||
|
||||
def test_allnans(self):
|
||||
# Check for FutureWarning
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
res = np.nansum([np.nan]*3, axis=None)
|
||||
assert_(res == 0, 'result is not 0')
|
||||
assert_(len(w) == 0, 'warning raised')
|
||||
# Check scalar
|
||||
res = np.nansum(np.nan)
|
||||
assert_(res == 0, 'result is not 0')
|
||||
assert_(len(w) == 0, 'warning raised')
|
||||
# Check there is no warning for not all-nan
|
||||
np.nansum([0]*3, axis=None)
|
||||
assert_(len(w) == 0, 'unwanted warning raised')
|
||||
|
||||
def test_empty(self):
|
||||
for f, tgt_value in zip([np.nansum, np.nanprod], [0, 1]):
|
||||
mat = np.zeros((0, 3))
|
||||
tgt = [tgt_value]*3
|
||||
res = f(mat, axis=0)
|
||||
assert_equal(res, tgt)
|
||||
tgt = []
|
||||
res = f(mat, axis=1)
|
||||
assert_equal(res, tgt)
|
||||
tgt = tgt_value
|
||||
res = f(mat, axis=None)
|
||||
assert_equal(res, tgt)
|
||||
|
||||
|
||||
class TestNanFunctions_CumSumProd(SharedNanFunctionsTestsMixin):
|
||||
|
||||
nanfuncs = [np.nancumsum, np.nancumprod]
|
||||
stdfuncs = [np.cumsum, np.cumprod]
|
||||
|
||||
def test_allnans(self):
|
||||
for f, tgt_value in zip(self.nanfuncs, [0, 1]):
|
||||
# Unlike other nan-functions, sum/prod/cumsum/cumprod don't warn on all nan input
|
||||
with assert_no_warnings():
|
||||
res = f([np.nan]*3, axis=None)
|
||||
tgt = tgt_value*np.ones((3))
|
||||
assert_(np.array_equal(res, tgt), 'result is not %s * np.ones((3))' % (tgt_value))
|
||||
# Check scalar
|
||||
res = f(np.nan)
|
||||
tgt = tgt_value*np.ones((1))
|
||||
assert_(np.array_equal(res, tgt), 'result is not %s * np.ones((1))' % (tgt_value))
|
||||
# Check there is no warning for not all-nan
|
||||
f([0]*3, axis=None)
|
||||
|
||||
def test_empty(self):
|
||||
for f, tgt_value in zip(self.nanfuncs, [0, 1]):
|
||||
mat = np.zeros((0, 3))
|
||||
tgt = tgt_value*np.ones((0, 3))
|
||||
res = f(mat, axis=0)
|
||||
assert_equal(res, tgt)
|
||||
tgt = mat
|
||||
res = f(mat, axis=1)
|
||||
assert_equal(res, tgt)
|
||||
tgt = np.zeros((0))
|
||||
res = f(mat, axis=None)
|
||||
assert_equal(res, tgt)
|
||||
|
||||
def test_keepdims(self):
|
||||
for f, g in zip(self.nanfuncs, self.stdfuncs):
|
||||
mat = np.eye(3)
|
||||
for axis in [None, 0, 1]:
|
||||
tgt = f(mat, axis=axis, out=None)
|
||||
res = g(mat, axis=axis, out=None)
|
||||
assert_(res.ndim == tgt.ndim)
|
||||
|
||||
for f in self.nanfuncs:
|
||||
d = np.ones((3, 5, 7, 11))
|
||||
# Randomly set some elements to NaN:
|
||||
rs = np.random.RandomState(0)
|
||||
d[rs.rand(*d.shape) < 0.5] = np.nan
|
||||
res = f(d, axis=None)
|
||||
assert_equal(res.shape, (1155,))
|
||||
for axis in np.arange(4):
|
||||
res = f(d, axis=axis)
|
||||
assert_equal(res.shape, (3, 5, 7, 11))
|
||||
|
||||
def test_result_values(self):
|
||||
for axis in (-2, -1, 0, 1, None):
|
||||
tgt = np.cumprod(_ndat_ones, axis=axis)
|
||||
res = np.nancumprod(_ndat, axis=axis)
|
||||
assert_almost_equal(res, tgt)
|
||||
tgt = np.cumsum(_ndat_zeros,axis=axis)
|
||||
res = np.nancumsum(_ndat, axis=axis)
|
||||
assert_almost_equal(res, tgt)
|
||||
|
||||
def test_out(self):
|
||||
mat = np.eye(3)
|
||||
for nf, rf in zip(self.nanfuncs, self.stdfuncs):
|
||||
resout = np.eye(3)
|
||||
for axis in (-2, -1, 0, 1):
|
||||
tgt = rf(mat, axis=axis)
|
||||
res = nf(mat, axis=axis, out=resout)
|
||||
assert_almost_equal(res, resout)
|
||||
assert_almost_equal(res, tgt)
|
||||
|
||||
|
||||
class TestNanFunctions_MeanVarStd(SharedNanFunctionsTestsMixin):
|
||||
|
||||
nanfuncs = [np.nanmean, np.nanvar, np.nanstd]
|
||||
stdfuncs = [np.mean, np.var, np.std]
|
||||
|
||||
def test_dtype_error(self):
|
||||
for f in self.nanfuncs:
|
||||
for dtype in [np.bool_, np.int_, np.object_]:
|
||||
assert_raises(TypeError, f, _ndat, axis=1, dtype=dtype)
|
||||
|
||||
def test_out_dtype_error(self):
|
||||
for f in self.nanfuncs:
|
||||
for dtype in [np.bool_, np.int_, np.object_]:
|
||||
out = np.empty(_ndat.shape[0], dtype=dtype)
|
||||
assert_raises(TypeError, f, _ndat, axis=1, out=out)
|
||||
|
||||
def test_ddof(self):
|
||||
nanfuncs = [np.nanvar, np.nanstd]
|
||||
stdfuncs = [np.var, np.std]
|
||||
for nf, rf in zip(nanfuncs, stdfuncs):
|
||||
for ddof in [0, 1]:
|
||||
tgt = [rf(d, ddof=ddof) for d in _rdat]
|
||||
res = nf(_ndat, axis=1, ddof=ddof)
|
||||
assert_almost_equal(res, tgt)
|
||||
|
||||
def test_ddof_too_big(self):
|
||||
nanfuncs = [np.nanvar, np.nanstd]
|
||||
stdfuncs = [np.var, np.std]
|
||||
dsize = [len(d) for d in _rdat]
|
||||
for nf, rf in zip(nanfuncs, stdfuncs):
|
||||
for ddof in range(5):
|
||||
with suppress_warnings() as sup:
|
||||
sup.record(RuntimeWarning)
|
||||
sup.filter(np.ComplexWarning)
|
||||
tgt = [ddof >= d for d in dsize]
|
||||
res = nf(_ndat, axis=1, ddof=ddof)
|
||||
assert_equal(np.isnan(res), tgt)
|
||||
if any(tgt):
|
||||
assert_(len(sup.log) == 1)
|
||||
else:
|
||||
assert_(len(sup.log) == 0)
|
||||
|
||||
def test_allnans(self):
|
||||
mat = np.array([np.nan]*9).reshape(3, 3)
|
||||
for f in self.nanfuncs:
|
||||
for axis in [None, 0, 1]:
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
assert_(np.isnan(f(mat, axis=axis)).all())
|
||||
assert_(len(w) == 1)
|
||||
assert_(issubclass(w[0].category, RuntimeWarning))
|
||||
# Check scalar
|
||||
assert_(np.isnan(f(np.nan)))
|
||||
assert_(len(w) == 2)
|
||||
assert_(issubclass(w[0].category, RuntimeWarning))
|
||||
|
||||
def test_empty(self):
|
||||
mat = np.zeros((0, 3))
|
||||
for f in self.nanfuncs:
|
||||
for axis in [0, None]:
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
assert_(np.isnan(f(mat, axis=axis)).all())
|
||||
assert_(len(w) == 1)
|
||||
assert_(issubclass(w[0].category, RuntimeWarning))
|
||||
for axis in [1]:
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
assert_equal(f(mat, axis=axis), np.zeros([]))
|
||||
assert_(len(w) == 0)
|
||||
|
||||
|
||||
class TestNanFunctions_Median(object):
|
||||
|
||||
def test_mutation(self):
|
||||
# Check that passed array is not modified.
|
||||
ndat = _ndat.copy()
|
||||
np.nanmedian(ndat)
|
||||
assert_equal(ndat, _ndat)
|
||||
|
||||
def test_keepdims(self):
|
||||
mat = np.eye(3)
|
||||
for axis in [None, 0, 1]:
|
||||
tgt = np.median(mat, axis=axis, out=None, overwrite_input=False)
|
||||
res = np.nanmedian(mat, axis=axis, out=None, overwrite_input=False)
|
||||
assert_(res.ndim == tgt.ndim)
|
||||
|
||||
d = np.ones((3, 5, 7, 11))
|
||||
# Randomly set some elements to NaN:
|
||||
w = np.random.random((4, 200)) * np.array(d.shape)[:, None]
|
||||
w = w.astype(np.intp)
|
||||
d[tuple(w)] = np.nan
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(RuntimeWarning)
|
||||
res = np.nanmedian(d, axis=None, keepdims=True)
|
||||
assert_equal(res.shape, (1, 1, 1, 1))
|
||||
res = np.nanmedian(d, axis=(0, 1), keepdims=True)
|
||||
assert_equal(res.shape, (1, 1, 7, 11))
|
||||
res = np.nanmedian(d, axis=(0, 3), keepdims=True)
|
||||
assert_equal(res.shape, (1, 5, 7, 1))
|
||||
res = np.nanmedian(d, axis=(1,), keepdims=True)
|
||||
assert_equal(res.shape, (3, 1, 7, 11))
|
||||
res = np.nanmedian(d, axis=(0, 1, 2, 3), keepdims=True)
|
||||
assert_equal(res.shape, (1, 1, 1, 1))
|
||||
res = np.nanmedian(d, axis=(0, 1, 3), keepdims=True)
|
||||
assert_equal(res.shape, (1, 1, 7, 1))
|
||||
|
||||
def test_out(self):
|
||||
mat = np.random.rand(3, 3)
|
||||
nan_mat = np.insert(mat, [0, 2], np.nan, axis=1)
|
||||
resout = np.zeros(3)
|
||||
tgt = np.median(mat, axis=1)
|
||||
res = np.nanmedian(nan_mat, axis=1, out=resout)
|
||||
assert_almost_equal(res, resout)
|
||||
assert_almost_equal(res, tgt)
|
||||
# 0-d output:
|
||||
resout = np.zeros(())
|
||||
tgt = np.median(mat, axis=None)
|
||||
res = np.nanmedian(nan_mat, axis=None, out=resout)
|
||||
assert_almost_equal(res, resout)
|
||||
assert_almost_equal(res, tgt)
|
||||
res = np.nanmedian(nan_mat, axis=(0, 1), out=resout)
|
||||
assert_almost_equal(res, resout)
|
||||
assert_almost_equal(res, tgt)
|
||||
|
||||
def test_small_large(self):
|
||||
# test the small and large code paths, current cutoff 400 elements
|
||||
for s in [5, 20, 51, 200, 1000]:
|
||||
d = np.random.randn(4, s)
|
||||
# Randomly set some elements to NaN:
|
||||
w = np.random.randint(0, d.size, size=d.size // 5)
|
||||
d.ravel()[w] = np.nan
|
||||
d[:,0] = 1. # ensure at least one good value
|
||||
# use normal median without nans to compare
|
||||
tgt = []
|
||||
for x in d:
|
||||
nonan = np.compress(~np.isnan(x), x)
|
||||
tgt.append(np.median(nonan, overwrite_input=True))
|
||||
|
||||
assert_array_equal(np.nanmedian(d, axis=-1), tgt)
|
||||
|
||||
def test_result_values(self):
|
||||
tgt = [np.median(d) for d in _rdat]
|
||||
res = np.nanmedian(_ndat, axis=1)
|
||||
assert_almost_equal(res, tgt)
|
||||
|
||||
def test_allnans(self):
|
||||
mat = np.array([np.nan]*9).reshape(3, 3)
|
||||
for axis in [None, 0, 1]:
|
||||
with suppress_warnings() as sup:
|
||||
sup.record(RuntimeWarning)
|
||||
|
||||
assert_(np.isnan(np.nanmedian(mat, axis=axis)).all())
|
||||
if axis is None:
|
||||
assert_(len(sup.log) == 1)
|
||||
else:
|
||||
assert_(len(sup.log) == 3)
|
||||
# Check scalar
|
||||
assert_(np.isnan(np.nanmedian(np.nan)))
|
||||
if axis is None:
|
||||
assert_(len(sup.log) == 2)
|
||||
else:
|
||||
assert_(len(sup.log) == 4)
|
||||
|
||||
def test_empty(self):
|
||||
mat = np.zeros((0, 3))
|
||||
for axis in [0, None]:
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
assert_(np.isnan(np.nanmedian(mat, axis=axis)).all())
|
||||
assert_(len(w) == 1)
|
||||
assert_(issubclass(w[0].category, RuntimeWarning))
|
||||
for axis in [1]:
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
assert_equal(np.nanmedian(mat, axis=axis), np.zeros([]))
|
||||
assert_(len(w) == 0)
|
||||
|
||||
def test_scalar(self):
|
||||
assert_(np.nanmedian(0.) == 0.)
|
||||
|
||||
def test_extended_axis_invalid(self):
|
||||
d = np.ones((3, 5, 7, 11))
|
||||
assert_raises(np.AxisError, np.nanmedian, d, axis=-5)
|
||||
assert_raises(np.AxisError, np.nanmedian, d, axis=(0, -5))
|
||||
assert_raises(np.AxisError, np.nanmedian, d, axis=4)
|
||||
assert_raises(np.AxisError, np.nanmedian, d, axis=(0, 4))
|
||||
assert_raises(ValueError, np.nanmedian, d, axis=(1, 1))
|
||||
|
||||
def test_float_special(self):
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(RuntimeWarning)
|
||||
for inf in [np.inf, -np.inf]:
|
||||
a = np.array([[inf, np.nan], [np.nan, np.nan]])
|
||||
assert_equal(np.nanmedian(a, axis=0), [inf, np.nan])
|
||||
assert_equal(np.nanmedian(a, axis=1), [inf, np.nan])
|
||||
assert_equal(np.nanmedian(a), inf)
|
||||
|
||||
# minimum fill value check
|
||||
a = np.array([[np.nan, np.nan, inf],
|
||||
[np.nan, np.nan, inf]])
|
||||
assert_equal(np.nanmedian(a), inf)
|
||||
assert_equal(np.nanmedian(a, axis=0), [np.nan, np.nan, inf])
|
||||
assert_equal(np.nanmedian(a, axis=1), inf)
|
||||
|
||||
# no mask path
|
||||
a = np.array([[inf, inf], [inf, inf]])
|
||||
assert_equal(np.nanmedian(a, axis=1), inf)
|
||||
|
||||
a = np.array([[inf, 7, -inf, -9],
|
||||
[-10, np.nan, np.nan, 5],
|
||||
[4, np.nan, np.nan, inf]],
|
||||
dtype=np.float32)
|
||||
if inf > 0:
|
||||
assert_equal(np.nanmedian(a, axis=0), [4., 7., -inf, 5.])
|
||||
assert_equal(np.nanmedian(a), 4.5)
|
||||
else:
|
||||
assert_equal(np.nanmedian(a, axis=0), [-10., 7., -inf, -9.])
|
||||
assert_equal(np.nanmedian(a), -2.5)
|
||||
assert_equal(np.nanmedian(a, axis=-1), [-1., -2.5, inf])
|
||||
|
||||
for i in range(0, 10):
|
||||
for j in range(1, 10):
|
||||
a = np.array([([np.nan] * i) + ([inf] * j)] * 2)
|
||||
assert_equal(np.nanmedian(a), inf)
|
||||
assert_equal(np.nanmedian(a, axis=1), inf)
|
||||
assert_equal(np.nanmedian(a, axis=0),
|
||||
([np.nan] * i) + [inf] * j)
|
||||
|
||||
a = np.array([([np.nan] * i) + ([-inf] * j)] * 2)
|
||||
assert_equal(np.nanmedian(a), -inf)
|
||||
assert_equal(np.nanmedian(a, axis=1), -inf)
|
||||
assert_equal(np.nanmedian(a, axis=0),
|
||||
([np.nan] * i) + [-inf] * j)
|
||||
|
||||
|
||||
class TestNanFunctions_Percentile(object):
|
||||
|
||||
def test_mutation(self):
|
||||
# Check that passed array is not modified.
|
||||
ndat = _ndat.copy()
|
||||
np.nanpercentile(ndat, 30)
|
||||
assert_equal(ndat, _ndat)
|
||||
|
||||
def test_keepdims(self):
|
||||
mat = np.eye(3)
|
||||
for axis in [None, 0, 1]:
|
||||
tgt = np.percentile(mat, 70, axis=axis, out=None,
|
||||
overwrite_input=False)
|
||||
res = np.nanpercentile(mat, 70, axis=axis, out=None,
|
||||
overwrite_input=False)
|
||||
assert_(res.ndim == tgt.ndim)
|
||||
|
||||
d = np.ones((3, 5, 7, 11))
|
||||
# Randomly set some elements to NaN:
|
||||
w = np.random.random((4, 200)) * np.array(d.shape)[:, None]
|
||||
w = w.astype(np.intp)
|
||||
d[tuple(w)] = np.nan
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(RuntimeWarning)
|
||||
res = np.nanpercentile(d, 90, axis=None, keepdims=True)
|
||||
assert_equal(res.shape, (1, 1, 1, 1))
|
||||
res = np.nanpercentile(d, 90, axis=(0, 1), keepdims=True)
|
||||
assert_equal(res.shape, (1, 1, 7, 11))
|
||||
res = np.nanpercentile(d, 90, axis=(0, 3), keepdims=True)
|
||||
assert_equal(res.shape, (1, 5, 7, 1))
|
||||
res = np.nanpercentile(d, 90, axis=(1,), keepdims=True)
|
||||
assert_equal(res.shape, (3, 1, 7, 11))
|
||||
res = np.nanpercentile(d, 90, axis=(0, 1, 2, 3), keepdims=True)
|
||||
assert_equal(res.shape, (1, 1, 1, 1))
|
||||
res = np.nanpercentile(d, 90, axis=(0, 1, 3), keepdims=True)
|
||||
assert_equal(res.shape, (1, 1, 7, 1))
|
||||
|
||||
def test_out(self):
|
||||
mat = np.random.rand(3, 3)
|
||||
nan_mat = np.insert(mat, [0, 2], np.nan, axis=1)
|
||||
resout = np.zeros(3)
|
||||
tgt = np.percentile(mat, 42, axis=1)
|
||||
res = np.nanpercentile(nan_mat, 42, axis=1, out=resout)
|
||||
assert_almost_equal(res, resout)
|
||||
assert_almost_equal(res, tgt)
|
||||
# 0-d output:
|
||||
resout = np.zeros(())
|
||||
tgt = np.percentile(mat, 42, axis=None)
|
||||
res = np.nanpercentile(nan_mat, 42, axis=None, out=resout)
|
||||
assert_almost_equal(res, resout)
|
||||
assert_almost_equal(res, tgt)
|
||||
res = np.nanpercentile(nan_mat, 42, axis=(0, 1), out=resout)
|
||||
assert_almost_equal(res, resout)
|
||||
assert_almost_equal(res, tgt)
|
||||
|
||||
def test_result_values(self):
|
||||
tgt = [np.percentile(d, 28) for d in _rdat]
|
||||
res = np.nanpercentile(_ndat, 28, axis=1)
|
||||
assert_almost_equal(res, tgt)
|
||||
# Transpose the array to fit the output convention of numpy.percentile
|
||||
tgt = np.transpose([np.percentile(d, (28, 98)) for d in _rdat])
|
||||
res = np.nanpercentile(_ndat, (28, 98), axis=1)
|
||||
assert_almost_equal(res, tgt)
|
||||
|
||||
def test_allnans(self):
|
||||
mat = np.array([np.nan]*9).reshape(3, 3)
|
||||
for axis in [None, 0, 1]:
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
assert_(np.isnan(np.nanpercentile(mat, 60, axis=axis)).all())
|
||||
if axis is None:
|
||||
assert_(len(w) == 1)
|
||||
else:
|
||||
assert_(len(w) == 3)
|
||||
assert_(issubclass(w[0].category, RuntimeWarning))
|
||||
# Check scalar
|
||||
assert_(np.isnan(np.nanpercentile(np.nan, 60)))
|
||||
if axis is None:
|
||||
assert_(len(w) == 2)
|
||||
else:
|
||||
assert_(len(w) == 4)
|
||||
assert_(issubclass(w[0].category, RuntimeWarning))
|
||||
|
||||
def test_empty(self):
|
||||
mat = np.zeros((0, 3))
|
||||
for axis in [0, None]:
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
assert_(np.isnan(np.nanpercentile(mat, 40, axis=axis)).all())
|
||||
assert_(len(w) == 1)
|
||||
assert_(issubclass(w[0].category, RuntimeWarning))
|
||||
for axis in [1]:
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
assert_equal(np.nanpercentile(mat, 40, axis=axis), np.zeros([]))
|
||||
assert_(len(w) == 0)
|
||||
|
||||
def test_scalar(self):
|
||||
assert_equal(np.nanpercentile(0., 100), 0.)
|
||||
a = np.arange(6)
|
||||
r = np.nanpercentile(a, 50, axis=0)
|
||||
assert_equal(r, 2.5)
|
||||
assert_(np.isscalar(r))
|
||||
|
||||
def test_extended_axis_invalid(self):
|
||||
d = np.ones((3, 5, 7, 11))
|
||||
assert_raises(np.AxisError, np.nanpercentile, d, q=5, axis=-5)
|
||||
assert_raises(np.AxisError, np.nanpercentile, d, q=5, axis=(0, -5))
|
||||
assert_raises(np.AxisError, np.nanpercentile, d, q=5, axis=4)
|
||||
assert_raises(np.AxisError, np.nanpercentile, d, q=5, axis=(0, 4))
|
||||
assert_raises(ValueError, np.nanpercentile, d, q=5, axis=(1, 1))
|
||||
|
||||
def test_multiple_percentiles(self):
|
||||
perc = [50, 100]
|
||||
mat = np.ones((4, 3))
|
||||
nan_mat = np.nan * mat
|
||||
# For checking consistency in higher dimensional case
|
||||
large_mat = np.ones((3, 4, 5))
|
||||
large_mat[:, 0:2:4, :] = 0
|
||||
large_mat[:, :, 3:] *= 2
|
||||
for axis in [None, 0, 1]:
|
||||
for keepdim in [False, True]:
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(RuntimeWarning, "All-NaN slice encountered")
|
||||
val = np.percentile(mat, perc, axis=axis, keepdims=keepdim)
|
||||
nan_val = np.nanpercentile(nan_mat, perc, axis=axis,
|
||||
keepdims=keepdim)
|
||||
assert_equal(nan_val.shape, val.shape)
|
||||
|
||||
val = np.percentile(large_mat, perc, axis=axis,
|
||||
keepdims=keepdim)
|
||||
nan_val = np.nanpercentile(large_mat, perc, axis=axis,
|
||||
keepdims=keepdim)
|
||||
assert_equal(nan_val, val)
|
||||
|
||||
megamat = np.ones((3, 4, 5, 6))
|
||||
assert_equal(np.nanpercentile(megamat, perc, axis=(1, 2)).shape, (2, 3, 6))
|
||||
|
||||
|
||||
class TestNanFunctions_Quantile(object):
|
||||
# most of this is already tested by TestPercentile
|
||||
|
||||
def test_regression(self):
|
||||
ar = np.arange(24).reshape(2, 3, 4).astype(float)
|
||||
ar[0][1] = np.nan
|
||||
|
||||
assert_equal(np.nanquantile(ar, q=0.5), np.nanpercentile(ar, q=50))
|
||||
assert_equal(np.nanquantile(ar, q=0.5, axis=0),
|
||||
np.nanpercentile(ar, q=50, axis=0))
|
||||
assert_equal(np.nanquantile(ar, q=0.5, axis=1),
|
||||
np.nanpercentile(ar, q=50, axis=1))
|
||||
assert_equal(np.nanquantile(ar, q=[0.5], axis=1),
|
||||
np.nanpercentile(ar, q=[50], axis=1))
|
||||
assert_equal(np.nanquantile(ar, q=[0.25, 0.5, 0.75], axis=1),
|
||||
np.nanpercentile(ar, q=[25, 50, 75], axis=1))
|
||||
|
||||
def test_basic(self):
|
||||
x = np.arange(8) * 0.5
|
||||
assert_equal(np.nanquantile(x, 0), 0.)
|
||||
assert_equal(np.nanquantile(x, 1), 3.5)
|
||||
assert_equal(np.nanquantile(x, 0.5), 1.75)
|
||||
|
||||
def test_no_p_overwrite(self):
|
||||
# this is worth retesting, because quantile does not make a copy
|
||||
p0 = np.array([0, 0.75, 0.25, 0.5, 1.0])
|
||||
p = p0.copy()
|
||||
np.nanquantile(np.arange(100.), p, interpolation="midpoint")
|
||||
assert_array_equal(p, p0)
|
||||
|
||||
p0 = p0.tolist()
|
||||
p = p.tolist()
|
||||
np.nanquantile(np.arange(100.), p, interpolation="midpoint")
|
||||
assert_array_equal(p, p0)
|
||||
@@ -0,0 +1,268 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import assert_array_equal, assert_equal, assert_raises
|
||||
|
||||
|
||||
def test_packbits():
|
||||
# Copied from the docstring.
|
||||
a = [[[1, 0, 1], [0, 1, 0]],
|
||||
[[1, 1, 0], [0, 0, 1]]]
|
||||
for dt in '?bBhHiIlLqQ':
|
||||
arr = np.array(a, dtype=dt)
|
||||
b = np.packbits(arr, axis=-1)
|
||||
assert_equal(b.dtype, np.uint8)
|
||||
assert_array_equal(b, np.array([[[160], [64]], [[192], [32]]]))
|
||||
|
||||
assert_raises(TypeError, np.packbits, np.array(a, dtype=float))
|
||||
|
||||
|
||||
def test_packbits_empty():
|
||||
shapes = [
|
||||
(0,), (10, 20, 0), (10, 0, 20), (0, 10, 20), (20, 0, 0), (0, 20, 0),
|
||||
(0, 0, 20), (0, 0, 0),
|
||||
]
|
||||
for dt in '?bBhHiIlLqQ':
|
||||
for shape in shapes:
|
||||
a = np.empty(shape, dtype=dt)
|
||||
b = np.packbits(a)
|
||||
assert_equal(b.dtype, np.uint8)
|
||||
assert_equal(b.shape, (0,))
|
||||
|
||||
|
||||
def test_packbits_empty_with_axis():
|
||||
# Original shapes and lists of packed shapes for different axes.
|
||||
shapes = [
|
||||
((0,), [(0,)]),
|
||||
((10, 20, 0), [(2, 20, 0), (10, 3, 0), (10, 20, 0)]),
|
||||
((10, 0, 20), [(2, 0, 20), (10, 0, 20), (10, 0, 3)]),
|
||||
((0, 10, 20), [(0, 10, 20), (0, 2, 20), (0, 10, 3)]),
|
||||
((20, 0, 0), [(3, 0, 0), (20, 0, 0), (20, 0, 0)]),
|
||||
((0, 20, 0), [(0, 20, 0), (0, 3, 0), (0, 20, 0)]),
|
||||
((0, 0, 20), [(0, 0, 20), (0, 0, 20), (0, 0, 3)]),
|
||||
((0, 0, 0), [(0, 0, 0), (0, 0, 0), (0, 0, 0)]),
|
||||
]
|
||||
for dt in '?bBhHiIlLqQ':
|
||||
for in_shape, out_shapes in shapes:
|
||||
for ax, out_shape in enumerate(out_shapes):
|
||||
a = np.empty(in_shape, dtype=dt)
|
||||
b = np.packbits(a, axis=ax)
|
||||
assert_equal(b.dtype, np.uint8)
|
||||
assert_equal(b.shape, out_shape)
|
||||
|
||||
|
||||
def test_packbits_large():
|
||||
# test data large enough for 16 byte vectorization
|
||||
a = np.array([1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
|
||||
0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1,
|
||||
1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
|
||||
1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1,
|
||||
1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1,
|
||||
1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1,
|
||||
0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0,
|
||||
1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1,
|
||||
1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1,
|
||||
1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0,
|
||||
1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0])
|
||||
a = a.repeat(3)
|
||||
for dtype in '?bBhHiIlLqQ':
|
||||
arr = np.array(a, dtype=dtype)
|
||||
b = np.packbits(arr, axis=None)
|
||||
assert_equal(b.dtype, np.uint8)
|
||||
r = [252, 127, 192, 3, 254, 7, 252, 0, 7, 31, 240, 0, 28, 1, 255, 252,
|
||||
113, 248, 3, 255, 192, 28, 15, 192, 28, 126, 0, 224, 127, 255,
|
||||
227, 142, 7, 31, 142, 63, 28, 126, 56, 227, 240, 0, 227, 128, 63,
|
||||
224, 14, 56, 252, 112, 56, 255, 241, 248, 3, 240, 56, 224, 112,
|
||||
63, 255, 255, 199, 224, 14, 0, 31, 143, 192, 3, 255, 199, 0, 1,
|
||||
255, 224, 1, 255, 252, 126, 63, 0, 1, 192, 252, 14, 63, 0, 15,
|
||||
199, 252, 113, 255, 3, 128, 56, 252, 14, 7, 0, 113, 255, 255, 142, 56, 227,
|
||||
129, 248, 227, 129, 199, 31, 128]
|
||||
assert_array_equal(b, r)
|
||||
# equal for size being multiple of 8
|
||||
assert_array_equal(np.unpackbits(b)[:-4], a)
|
||||
|
||||
# check last byte of different remainders (16 byte vectorization)
|
||||
b = [np.packbits(arr[:-i], axis=None)[-1] for i in range(1, 16)]
|
||||
assert_array_equal(b, [128, 128, 128, 31, 30, 28, 24, 16, 0, 0, 0, 199,
|
||||
198, 196, 192])
|
||||
|
||||
|
||||
arr = arr.reshape(36, 25)
|
||||
b = np.packbits(arr, axis=0)
|
||||
assert_equal(b.dtype, np.uint8)
|
||||
assert_array_equal(b, [[190, 186, 178, 178, 150, 215, 87, 83, 83, 195,
|
||||
199, 206, 204, 204, 140, 140, 136, 136, 8, 40, 105,
|
||||
107, 75, 74, 88],
|
||||
[72, 216, 248, 241, 227, 195, 202, 90, 90, 83,
|
||||
83, 119, 127, 109, 73, 64, 208, 244, 189, 45,
|
||||
41, 104, 122, 90, 18],
|
||||
[113, 120, 248, 216, 152, 24, 60, 52, 182, 150,
|
||||
150, 150, 146, 210, 210, 246, 255, 255, 223,
|
||||
151, 21, 17, 17, 131, 163],
|
||||
[214, 210, 210, 64, 68, 5, 5, 1, 72, 88, 92,
|
||||
92, 78, 110, 39, 181, 149, 220, 222, 218, 218,
|
||||
202, 234, 170, 168],
|
||||
[0, 128, 128, 192, 80, 112, 48, 160, 160, 224,
|
||||
240, 208, 144, 128, 160, 224, 240, 208, 144,
|
||||
144, 176, 240, 224, 192, 128]])
|
||||
|
||||
b = np.packbits(arr, axis=1)
|
||||
assert_equal(b.dtype, np.uint8)
|
||||
assert_array_equal(b, [[252, 127, 192, 0],
|
||||
[ 7, 252, 15, 128],
|
||||
[240, 0, 28, 0],
|
||||
[255, 128, 0, 128],
|
||||
[192, 31, 255, 128],
|
||||
[142, 63, 0, 0],
|
||||
[255, 240, 7, 0],
|
||||
[ 7, 224, 14, 0],
|
||||
[126, 0, 224, 0],
|
||||
[255, 255, 199, 0],
|
||||
[ 56, 28, 126, 0],
|
||||
[113, 248, 227, 128],
|
||||
[227, 142, 63, 0],
|
||||
[ 0, 28, 112, 0],
|
||||
[ 15, 248, 3, 128],
|
||||
[ 28, 126, 56, 0],
|
||||
[ 56, 255, 241, 128],
|
||||
[240, 7, 224, 0],
|
||||
[227, 129, 192, 128],
|
||||
[255, 255, 254, 0],
|
||||
[126, 0, 224, 0],
|
||||
[ 3, 241, 248, 0],
|
||||
[ 0, 255, 241, 128],
|
||||
[128, 0, 255, 128],
|
||||
[224, 1, 255, 128],
|
||||
[248, 252, 126, 0],
|
||||
[ 0, 7, 3, 128],
|
||||
[224, 113, 248, 0],
|
||||
[ 0, 252, 127, 128],
|
||||
[142, 63, 224, 0],
|
||||
[224, 14, 63, 0],
|
||||
[ 7, 3, 128, 0],
|
||||
[113, 255, 255, 128],
|
||||
[ 28, 113, 199, 0],
|
||||
[ 7, 227, 142, 0],
|
||||
[ 14, 56, 252, 0]])
|
||||
|
||||
arr = arr.T.copy()
|
||||
b = np.packbits(arr, axis=0)
|
||||
assert_equal(b.dtype, np.uint8)
|
||||
assert_array_equal(b, [[252, 7, 240, 255, 192, 142, 255, 7, 126, 255,
|
||||
56, 113, 227, 0, 15, 28, 56, 240, 227, 255,
|
||||
126, 3, 0, 128, 224, 248, 0, 224, 0, 142, 224,
|
||||
7, 113, 28, 7, 14],
|
||||
[127, 252, 0, 128, 31, 63, 240, 224, 0, 255,
|
||||
28, 248, 142, 28, 248, 126, 255, 7, 129, 255,
|
||||
0, 241, 255, 0, 1, 252, 7, 113, 252, 63, 14,
|
||||
3, 255, 113, 227, 56],
|
||||
[192, 15, 28, 0, 255, 0, 7, 14, 224, 199, 126,
|
||||
227, 63, 112, 3, 56, 241, 224, 192, 254, 224,
|
||||
248, 241, 255, 255, 126, 3, 248, 127, 224, 63,
|
||||
128, 255, 199, 142, 252],
|
||||
[0, 128, 0, 128, 128, 0, 0, 0, 0, 0, 0, 128, 0,
|
||||
0, 128, 0, 128, 0, 128, 0, 0, 0, 128, 128,
|
||||
128, 0, 128, 0, 128, 0, 0, 0, 128, 0, 0, 0]])
|
||||
|
||||
b = np.packbits(arr, axis=1)
|
||||
assert_equal(b.dtype, np.uint8)
|
||||
assert_array_equal(b, [[190, 72, 113, 214, 0],
|
||||
[186, 216, 120, 210, 128],
|
||||
[178, 248, 248, 210, 128],
|
||||
[178, 241, 216, 64, 192],
|
||||
[150, 227, 152, 68, 80],
|
||||
[215, 195, 24, 5, 112],
|
||||
[ 87, 202, 60, 5, 48],
|
||||
[ 83, 90, 52, 1, 160],
|
||||
[ 83, 90, 182, 72, 160],
|
||||
[195, 83, 150, 88, 224],
|
||||
[199, 83, 150, 92, 240],
|
||||
[206, 119, 150, 92, 208],
|
||||
[204, 127, 146, 78, 144],
|
||||
[204, 109, 210, 110, 128],
|
||||
[140, 73, 210, 39, 160],
|
||||
[140, 64, 246, 181, 224],
|
||||
[136, 208, 255, 149, 240],
|
||||
[136, 244, 255, 220, 208],
|
||||
[ 8, 189, 223, 222, 144],
|
||||
[ 40, 45, 151, 218, 144],
|
||||
[105, 41, 21, 218, 176],
|
||||
[107, 104, 17, 202, 240],
|
||||
[ 75, 122, 17, 234, 224],
|
||||
[ 74, 90, 131, 170, 192],
|
||||
[ 88, 18, 163, 168, 128]])
|
||||
|
||||
|
||||
# result is the same if input is multiplied with a nonzero value
|
||||
for dtype in 'bBhHiIlLqQ':
|
||||
arr = np.array(a, dtype=dtype)
|
||||
rnd = np.random.randint(low=np.iinfo(dtype).min,
|
||||
high=np.iinfo(dtype).max, size=arr.size,
|
||||
dtype=dtype)
|
||||
rnd[rnd == 0] = 1
|
||||
arr *= rnd.astype(dtype)
|
||||
b = np.packbits(arr, axis=-1)
|
||||
assert_array_equal(np.unpackbits(b)[:-4], a)
|
||||
|
||||
assert_raises(TypeError, np.packbits, np.array(a, dtype=float))
|
||||
|
||||
|
||||
def test_packbits_very_large():
|
||||
# test some with a larger arrays gh-8637
|
||||
# code is covered earlier but larger array makes crash on bug more likely
|
||||
for s in range(950, 1050):
|
||||
for dt in '?bBhHiIlLqQ':
|
||||
x = np.ones((200, s), dtype=bool)
|
||||
np.packbits(x, axis=1)
|
||||
|
||||
|
||||
def test_unpackbits():
|
||||
# Copied from the docstring.
|
||||
a = np.array([[2], [7], [23]], dtype=np.uint8)
|
||||
b = np.unpackbits(a, axis=1)
|
||||
assert_equal(b.dtype, np.uint8)
|
||||
assert_array_equal(b, np.array([[0, 0, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 1, 1, 1],
|
||||
[0, 0, 0, 1, 0, 1, 1, 1]]))
|
||||
|
||||
|
||||
def test_unpackbits_empty():
|
||||
a = np.empty((0,), dtype=np.uint8)
|
||||
b = np.unpackbits(a)
|
||||
assert_equal(b.dtype, np.uint8)
|
||||
assert_array_equal(b, np.empty((0,)))
|
||||
|
||||
|
||||
def test_unpackbits_empty_with_axis():
|
||||
# Lists of packed shapes for different axes and unpacked shapes.
|
||||
shapes = [
|
||||
([(0,)], (0,)),
|
||||
([(2, 24, 0), (16, 3, 0), (16, 24, 0)], (16, 24, 0)),
|
||||
([(2, 0, 24), (16, 0, 24), (16, 0, 3)], (16, 0, 24)),
|
||||
([(0, 16, 24), (0, 2, 24), (0, 16, 3)], (0, 16, 24)),
|
||||
([(3, 0, 0), (24, 0, 0), (24, 0, 0)], (24, 0, 0)),
|
||||
([(0, 24, 0), (0, 3, 0), (0, 24, 0)], (0, 24, 0)),
|
||||
([(0, 0, 24), (0, 0, 24), (0, 0, 3)], (0, 0, 24)),
|
||||
([(0, 0, 0), (0, 0, 0), (0, 0, 0)], (0, 0, 0)),
|
||||
]
|
||||
for in_shapes, out_shape in shapes:
|
||||
for ax, in_shape in enumerate(in_shapes):
|
||||
a = np.empty(in_shape, dtype=np.uint8)
|
||||
b = np.unpackbits(a, axis=ax)
|
||||
assert_equal(b.dtype, np.uint8)
|
||||
assert_equal(b.shape, out_shape)
|
||||
|
||||
|
||||
def test_unpackbits_large():
|
||||
# test all possible numbers via comparison to already tested packbits
|
||||
d = np.arange(277, dtype=np.uint8)
|
||||
assert_array_equal(np.packbits(np.unpackbits(d)), d)
|
||||
assert_array_equal(np.packbits(np.unpackbits(d[::2])), d[::2])
|
||||
d = np.tile(d, (3, 1))
|
||||
assert_array_equal(np.packbits(np.unpackbits(d, axis=1), axis=1), d)
|
||||
d = d.T.copy()
|
||||
assert_array_equal(np.packbits(np.unpackbits(d, axis=0), axis=0), d)
|
||||
@@ -0,0 +1,261 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import (
|
||||
assert_, assert_equal, assert_array_equal, assert_almost_equal,
|
||||
assert_array_almost_equal, assert_raises, assert_allclose
|
||||
)
|
||||
|
||||
|
||||
class TestPolynomial(object):
|
||||
def test_poly1d_str_and_repr(self):
|
||||
p = np.poly1d([1., 2, 3])
|
||||
assert_equal(repr(p), 'poly1d([1., 2., 3.])')
|
||||
assert_equal(str(p),
|
||||
' 2\n'
|
||||
'1 x + 2 x + 3')
|
||||
|
||||
q = np.poly1d([3., 2, 1])
|
||||
assert_equal(repr(q), 'poly1d([3., 2., 1.])')
|
||||
assert_equal(str(q),
|
||||
' 2\n'
|
||||
'3 x + 2 x + 1')
|
||||
|
||||
r = np.poly1d([1.89999 + 2j, -3j, -5.12345678, 2 + 1j])
|
||||
assert_equal(str(r),
|
||||
' 3 2\n'
|
||||
'(1.9 + 2j) x - 3j x - 5.123 x + (2 + 1j)')
|
||||
|
||||
assert_equal(str(np.poly1d([-3, -2, -1])),
|
||||
' 2\n'
|
||||
'-3 x - 2 x - 1')
|
||||
|
||||
def test_poly1d_resolution(self):
|
||||
p = np.poly1d([1., 2, 3])
|
||||
q = np.poly1d([3., 2, 1])
|
||||
assert_equal(p(0), 3.0)
|
||||
assert_equal(p(5), 38.0)
|
||||
assert_equal(q(0), 1.0)
|
||||
assert_equal(q(5), 86.0)
|
||||
|
||||
def test_poly1d_math(self):
|
||||
# here we use some simple coeffs to make calculations easier
|
||||
p = np.poly1d([1., 2, 4])
|
||||
q = np.poly1d([4., 2, 1])
|
||||
assert_equal(p/q, (np.poly1d([0.25]), np.poly1d([1.5, 3.75])))
|
||||
assert_equal(p.integ(), np.poly1d([1/3, 1., 4., 0.]))
|
||||
assert_equal(p.integ(1), np.poly1d([1/3, 1., 4., 0.]))
|
||||
|
||||
p = np.poly1d([1., 2, 3])
|
||||
q = np.poly1d([3., 2, 1])
|
||||
assert_equal(p * q, np.poly1d([3., 8., 14., 8., 3.]))
|
||||
assert_equal(p + q, np.poly1d([4., 4., 4.]))
|
||||
assert_equal(p - q, np.poly1d([-2., 0., 2.]))
|
||||
assert_equal(p ** 4, np.poly1d([1., 8., 36., 104., 214., 312., 324., 216., 81.]))
|
||||
assert_equal(p(q), np.poly1d([9., 12., 16., 8., 6.]))
|
||||
assert_equal(q(p), np.poly1d([3., 12., 32., 40., 34.]))
|
||||
assert_equal(p.deriv(), np.poly1d([2., 2.]))
|
||||
assert_equal(p.deriv(2), np.poly1d([2.]))
|
||||
assert_equal(np.polydiv(np.poly1d([1, 0, -1]), np.poly1d([1, 1])),
|
||||
(np.poly1d([1., -1.]), np.poly1d([0.])))
|
||||
|
||||
def test_poly1d_misc(self):
|
||||
p = np.poly1d([1., 2, 3])
|
||||
assert_equal(np.asarray(p), np.array([1., 2., 3.]))
|
||||
assert_equal(len(p), 2)
|
||||
assert_equal((p[0], p[1], p[2], p[3]), (3.0, 2.0, 1.0, 0))
|
||||
|
||||
def test_poly1d_variable_arg(self):
|
||||
q = np.poly1d([1., 2, 3], variable='y')
|
||||
assert_equal(str(q),
|
||||
' 2\n'
|
||||
'1 y + 2 y + 3')
|
||||
q = np.poly1d([1., 2, 3], variable='lambda')
|
||||
assert_equal(str(q),
|
||||
' 2\n'
|
||||
'1 lambda + 2 lambda + 3')
|
||||
|
||||
def test_poly(self):
|
||||
assert_array_almost_equal(np.poly([3, -np.sqrt(2), np.sqrt(2)]),
|
||||
[1, -3, -2, 6])
|
||||
|
||||
# From matlab docs
|
||||
A = [[1, 2, 3], [4, 5, 6], [7, 8, 0]]
|
||||
assert_array_almost_equal(np.poly(A), [1, -6, -72, -27])
|
||||
|
||||
# Should produce real output for perfect conjugates
|
||||
assert_(np.isrealobj(np.poly([+1.082j, +2.613j, -2.613j, -1.082j])))
|
||||
assert_(np.isrealobj(np.poly([0+1j, -0+-1j, 1+2j,
|
||||
1-2j, 1.+3.5j, 1-3.5j])))
|
||||
assert_(np.isrealobj(np.poly([1j, -1j, 1+2j, 1-2j, 1+3j, 1-3.j])))
|
||||
assert_(np.isrealobj(np.poly([1j, -1j, 1+2j, 1-2j])))
|
||||
assert_(np.isrealobj(np.poly([1j, -1j, 2j, -2j])))
|
||||
assert_(np.isrealobj(np.poly([1j, -1j])))
|
||||
assert_(np.isrealobj(np.poly([1, -1])))
|
||||
|
||||
assert_(np.iscomplexobj(np.poly([1j, -1.0000001j])))
|
||||
|
||||
np.random.seed(42)
|
||||
a = np.random.randn(100) + 1j*np.random.randn(100)
|
||||
assert_(np.isrealobj(np.poly(np.concatenate((a, np.conjugate(a))))))
|
||||
|
||||
def test_roots(self):
|
||||
assert_array_equal(np.roots([1, 0, 0]), [0, 0])
|
||||
|
||||
def test_str_leading_zeros(self):
|
||||
p = np.poly1d([4, 3, 2, 1])
|
||||
p[3] = 0
|
||||
assert_equal(str(p),
|
||||
" 2\n"
|
||||
"3 x + 2 x + 1")
|
||||
|
||||
p = np.poly1d([1, 2])
|
||||
p[0] = 0
|
||||
p[1] = 0
|
||||
assert_equal(str(p), " \n0")
|
||||
|
||||
def test_polyfit(self):
|
||||
c = np.array([3., 2., 1.])
|
||||
x = np.linspace(0, 2, 7)
|
||||
y = np.polyval(c, x)
|
||||
err = [1, -1, 1, -1, 1, -1, 1]
|
||||
weights = np.arange(8, 1, -1)**2/7.0
|
||||
|
||||
# Check exception when too few points for variance estimate. Note that
|
||||
# the estimate requires the number of data points to exceed
|
||||
# degree + 1
|
||||
assert_raises(ValueError, np.polyfit,
|
||||
[1], [1], deg=0, cov=True)
|
||||
|
||||
# check 1D case
|
||||
m, cov = np.polyfit(x, y+err, 2, cov=True)
|
||||
est = [3.8571, 0.2857, 1.619]
|
||||
assert_almost_equal(est, m, decimal=4)
|
||||
val0 = [[ 1.4694, -2.9388, 0.8163],
|
||||
[-2.9388, 6.3673, -2.1224],
|
||||
[ 0.8163, -2.1224, 1.161 ]]
|
||||
assert_almost_equal(val0, cov, decimal=4)
|
||||
|
||||
m2, cov2 = np.polyfit(x, y+err, 2, w=weights, cov=True)
|
||||
assert_almost_equal([4.8927, -1.0177, 1.7768], m2, decimal=4)
|
||||
val = [[ 4.3964, -5.0052, 0.4878],
|
||||
[-5.0052, 6.8067, -0.9089],
|
||||
[ 0.4878, -0.9089, 0.3337]]
|
||||
assert_almost_equal(val, cov2, decimal=4)
|
||||
|
||||
m3, cov3 = np.polyfit(x, y+err, 2, w=weights, cov="unscaled")
|
||||
assert_almost_equal([4.8927, -1.0177, 1.7768], m3, decimal=4)
|
||||
val = [[ 0.1473, -0.1677, 0.0163],
|
||||
[-0.1677, 0.228 , -0.0304],
|
||||
[ 0.0163, -0.0304, 0.0112]]
|
||||
assert_almost_equal(val, cov3, decimal=4)
|
||||
|
||||
# check 2D (n,1) case
|
||||
y = y[:, np.newaxis]
|
||||
c = c[:, np.newaxis]
|
||||
assert_almost_equal(c, np.polyfit(x, y, 2))
|
||||
# check 2D (n,2) case
|
||||
yy = np.concatenate((y, y), axis=1)
|
||||
cc = np.concatenate((c, c), axis=1)
|
||||
assert_almost_equal(cc, np.polyfit(x, yy, 2))
|
||||
|
||||
m, cov = np.polyfit(x, yy + np.array(err)[:, np.newaxis], 2, cov=True)
|
||||
assert_almost_equal(est, m[:, 0], decimal=4)
|
||||
assert_almost_equal(est, m[:, 1], decimal=4)
|
||||
assert_almost_equal(val0, cov[:, :, 0], decimal=4)
|
||||
assert_almost_equal(val0, cov[:, :, 1], decimal=4)
|
||||
|
||||
# check order 1 (deg=0) case, were the analytic results are simple
|
||||
np.random.seed(123)
|
||||
y = np.random.normal(size=(4, 10000))
|
||||
mean, cov = np.polyfit(np.zeros(y.shape[0]), y, deg=0, cov=True)
|
||||
# Should get sigma_mean = sigma/sqrt(N) = 1./sqrt(4) = 0.5.
|
||||
assert_allclose(mean.std(), 0.5, atol=0.01)
|
||||
assert_allclose(np.sqrt(cov.mean()), 0.5, atol=0.01)
|
||||
# Without scaling, since reduced chi2 is 1, the result should be the same.
|
||||
mean, cov = np.polyfit(np.zeros(y.shape[0]), y, w=np.ones(y.shape[0]),
|
||||
deg=0, cov="unscaled")
|
||||
assert_allclose(mean.std(), 0.5, atol=0.01)
|
||||
assert_almost_equal(np.sqrt(cov.mean()), 0.5)
|
||||
# If we estimate our errors wrong, no change with scaling:
|
||||
w = np.full(y.shape[0], 1./0.5)
|
||||
mean, cov = np.polyfit(np.zeros(y.shape[0]), y, w=w, deg=0, cov=True)
|
||||
assert_allclose(mean.std(), 0.5, atol=0.01)
|
||||
assert_allclose(np.sqrt(cov.mean()), 0.5, atol=0.01)
|
||||
# But if we do not scale, our estimate for the error in the mean will
|
||||
# differ.
|
||||
mean, cov = np.polyfit(np.zeros(y.shape[0]), y, w=w, deg=0, cov="unscaled")
|
||||
assert_allclose(mean.std(), 0.5, atol=0.01)
|
||||
assert_almost_equal(np.sqrt(cov.mean()), 0.25)
|
||||
|
||||
def test_objects(self):
|
||||
from decimal import Decimal
|
||||
p = np.poly1d([Decimal('4.0'), Decimal('3.0'), Decimal('2.0')])
|
||||
p2 = p * Decimal('1.333333333333333')
|
||||
assert_(p2[1] == Decimal("3.9999999999999990"))
|
||||
p2 = p.deriv()
|
||||
assert_(p2[1] == Decimal('8.0'))
|
||||
p2 = p.integ()
|
||||
assert_(p2[3] == Decimal("1.333333333333333333333333333"))
|
||||
assert_(p2[2] == Decimal('1.5'))
|
||||
assert_(np.issubdtype(p2.coeffs.dtype, np.object_))
|
||||
p = np.poly([Decimal(1), Decimal(2)])
|
||||
assert_equal(np.poly([Decimal(1), Decimal(2)]),
|
||||
[1, Decimal(-3), Decimal(2)])
|
||||
|
||||
def test_complex(self):
|
||||
p = np.poly1d([3j, 2j, 1j])
|
||||
p2 = p.integ()
|
||||
assert_((p2.coeffs == [1j, 1j, 1j, 0]).all())
|
||||
p2 = p.deriv()
|
||||
assert_((p2.coeffs == [6j, 2j]).all())
|
||||
|
||||
def test_integ_coeffs(self):
|
||||
p = np.poly1d([3, 2, 1])
|
||||
p2 = p.integ(3, k=[9, 7, 6])
|
||||
assert_(
|
||||
(p2.coeffs == [1/4./5., 1/3./4., 1/2./3., 9/1./2., 7, 6]).all())
|
||||
|
||||
def test_zero_dims(self):
|
||||
try:
|
||||
np.poly(np.zeros((0, 0)))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def test_poly_int_overflow(self):
|
||||
"""
|
||||
Regression test for gh-5096.
|
||||
"""
|
||||
v = np.arange(1, 21)
|
||||
assert_almost_equal(np.poly(v), np.poly(np.diag(v)))
|
||||
|
||||
def test_poly_eq(self):
|
||||
p = np.poly1d([1, 2, 3])
|
||||
p2 = np.poly1d([1, 2, 4])
|
||||
assert_equal(p == None, False)
|
||||
assert_equal(p != None, True)
|
||||
assert_equal(p == p, True)
|
||||
assert_equal(p == p2, False)
|
||||
assert_equal(p != p2, True)
|
||||
|
||||
def test_polydiv(self):
|
||||
b = np.poly1d([2, 6, 6, 1])
|
||||
a = np.poly1d([-1j, (1+2j), -(2+1j), 1])
|
||||
q, r = np.polydiv(b, a)
|
||||
assert_equal(q.coeffs.dtype, np.complex128)
|
||||
assert_equal(r.coeffs.dtype, np.complex128)
|
||||
assert_equal(q*a + r, b)
|
||||
|
||||
def test_poly_coeffs_immutable(self):
|
||||
""" Coefficients should not be modifiable """
|
||||
p = np.poly1d([1, 2, 3])
|
||||
|
||||
try:
|
||||
# despite throwing an exception, this used to change state
|
||||
p.coeffs += 1
|
||||
except Exception:
|
||||
pass
|
||||
assert_equal(p.coeffs, [1, 2, 3])
|
||||
|
||||
p.coeffs[2] += 10
|
||||
assert_equal(p.coeffs, [1, 2, 3])
|
||||
@@ -0,0 +1,911 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import pytest
|
||||
|
||||
import numpy as np
|
||||
import numpy.ma as ma
|
||||
from numpy.ma.mrecords import MaskedRecords
|
||||
from numpy.ma.testutils import assert_equal
|
||||
from numpy.testing import assert_, assert_raises
|
||||
from numpy.lib.recfunctions import (
|
||||
drop_fields, rename_fields, get_fieldstructure, recursive_fill_fields,
|
||||
find_duplicates, merge_arrays, append_fields, stack_arrays, join_by,
|
||||
repack_fields, unstructured_to_structured, structured_to_unstructured,
|
||||
apply_along_fields, require_fields, assign_fields_by_name)
|
||||
get_names = np.lib.recfunctions.get_names
|
||||
get_names_flat = np.lib.recfunctions.get_names_flat
|
||||
zip_descr = np.lib.recfunctions.zip_descr
|
||||
|
||||
|
||||
class TestRecFunctions(object):
|
||||
# Misc tests
|
||||
|
||||
def setup(self):
|
||||
x = np.array([1, 2, ])
|
||||
y = np.array([10, 20, 30])
|
||||
z = np.array([('A', 1.), ('B', 2.)],
|
||||
dtype=[('A', '|S3'), ('B', float)])
|
||||
w = np.array([(1, (2, 3.0)), (4, (5, 6.0))],
|
||||
dtype=[('a', int), ('b', [('ba', float), ('bb', int)])])
|
||||
self.data = (w, x, y, z)
|
||||
|
||||
def test_zip_descr(self):
|
||||
# Test zip_descr
|
||||
(w, x, y, z) = self.data
|
||||
|
||||
# Std array
|
||||
test = zip_descr((x, x), flatten=True)
|
||||
assert_equal(test,
|
||||
np.dtype([('', int), ('', int)]))
|
||||
test = zip_descr((x, x), flatten=False)
|
||||
assert_equal(test,
|
||||
np.dtype([('', int), ('', int)]))
|
||||
|
||||
# Std & flexible-dtype
|
||||
test = zip_descr((x, z), flatten=True)
|
||||
assert_equal(test,
|
||||
np.dtype([('', int), ('A', '|S3'), ('B', float)]))
|
||||
test = zip_descr((x, z), flatten=False)
|
||||
assert_equal(test,
|
||||
np.dtype([('', int),
|
||||
('', [('A', '|S3'), ('B', float)])]))
|
||||
|
||||
# Standard & nested dtype
|
||||
test = zip_descr((x, w), flatten=True)
|
||||
assert_equal(test,
|
||||
np.dtype([('', int),
|
||||
('a', int),
|
||||
('ba', float), ('bb', int)]))
|
||||
test = zip_descr((x, w), flatten=False)
|
||||
assert_equal(test,
|
||||
np.dtype([('', int),
|
||||
('', [('a', int),
|
||||
('b', [('ba', float), ('bb', int)])])]))
|
||||
|
||||
def test_drop_fields(self):
|
||||
# Test drop_fields
|
||||
a = np.array([(1, (2, 3.0)), (4, (5, 6.0))],
|
||||
dtype=[('a', int), ('b', [('ba', float), ('bb', int)])])
|
||||
|
||||
# A basic field
|
||||
test = drop_fields(a, 'a')
|
||||
control = np.array([((2, 3.0),), ((5, 6.0),)],
|
||||
dtype=[('b', [('ba', float), ('bb', int)])])
|
||||
assert_equal(test, control)
|
||||
|
||||
# Another basic field (but nesting two fields)
|
||||
test = drop_fields(a, 'b')
|
||||
control = np.array([(1,), (4,)], dtype=[('a', int)])
|
||||
assert_equal(test, control)
|
||||
|
||||
# A nested sub-field
|
||||
test = drop_fields(a, ['ba', ])
|
||||
control = np.array([(1, (3.0,)), (4, (6.0,))],
|
||||
dtype=[('a', int), ('b', [('bb', int)])])
|
||||
assert_equal(test, control)
|
||||
|
||||
# All the nested sub-field from a field: zap that field
|
||||
test = drop_fields(a, ['ba', 'bb'])
|
||||
control = np.array([(1,), (4,)], dtype=[('a', int)])
|
||||
assert_equal(test, control)
|
||||
|
||||
test = drop_fields(a, ['a', 'b'])
|
||||
assert_(test is None)
|
||||
|
||||
def test_rename_fields(self):
|
||||
# Test rename fields
|
||||
a = np.array([(1, (2, [3.0, 30.])), (4, (5, [6.0, 60.]))],
|
||||
dtype=[('a', int),
|
||||
('b', [('ba', float), ('bb', (float, 2))])])
|
||||
test = rename_fields(a, {'a': 'A', 'bb': 'BB'})
|
||||
newdtype = [('A', int), ('b', [('ba', float), ('BB', (float, 2))])]
|
||||
control = a.view(newdtype)
|
||||
assert_equal(test.dtype, newdtype)
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_get_names(self):
|
||||
# Test get_names
|
||||
ndtype = np.dtype([('A', '|S3'), ('B', float)])
|
||||
test = get_names(ndtype)
|
||||
assert_equal(test, ('A', 'B'))
|
||||
|
||||
ndtype = np.dtype([('a', int), ('b', [('ba', float), ('bb', int)])])
|
||||
test = get_names(ndtype)
|
||||
assert_equal(test, ('a', ('b', ('ba', 'bb'))))
|
||||
|
||||
def test_get_names_flat(self):
|
||||
# Test get_names_flat
|
||||
ndtype = np.dtype([('A', '|S3'), ('B', float)])
|
||||
test = get_names_flat(ndtype)
|
||||
assert_equal(test, ('A', 'B'))
|
||||
|
||||
ndtype = np.dtype([('a', int), ('b', [('ba', float), ('bb', int)])])
|
||||
test = get_names_flat(ndtype)
|
||||
assert_equal(test, ('a', 'b', 'ba', 'bb'))
|
||||
|
||||
def test_get_fieldstructure(self):
|
||||
# Test get_fieldstructure
|
||||
|
||||
# No nested fields
|
||||
ndtype = np.dtype([('A', '|S3'), ('B', float)])
|
||||
test = get_fieldstructure(ndtype)
|
||||
assert_equal(test, {'A': [], 'B': []})
|
||||
|
||||
# One 1-nested field
|
||||
ndtype = np.dtype([('A', int), ('B', [('BA', float), ('BB', '|S1')])])
|
||||
test = get_fieldstructure(ndtype)
|
||||
assert_equal(test, {'A': [], 'B': [], 'BA': ['B', ], 'BB': ['B']})
|
||||
|
||||
# One 2-nested fields
|
||||
ndtype = np.dtype([('A', int),
|
||||
('B', [('BA', int),
|
||||
('BB', [('BBA', int), ('BBB', int)])])])
|
||||
test = get_fieldstructure(ndtype)
|
||||
control = {'A': [], 'B': [], 'BA': ['B'], 'BB': ['B'],
|
||||
'BBA': ['B', 'BB'], 'BBB': ['B', 'BB']}
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_find_duplicates(self):
|
||||
# Test find_duplicates
|
||||
a = ma.array([(2, (2., 'B')), (1, (2., 'B')), (2, (2., 'B')),
|
||||
(1, (1., 'B')), (2, (2., 'B')), (2, (2., 'C'))],
|
||||
mask=[(0, (0, 0)), (0, (0, 0)), (0, (0, 0)),
|
||||
(0, (0, 0)), (1, (0, 0)), (0, (1, 0))],
|
||||
dtype=[('A', int), ('B', [('BA', float), ('BB', '|S1')])])
|
||||
|
||||
test = find_duplicates(a, ignoremask=False, return_index=True)
|
||||
control = [0, 2]
|
||||
assert_equal(sorted(test[-1]), control)
|
||||
assert_equal(test[0], a[test[-1]])
|
||||
|
||||
test = find_duplicates(a, key='A', return_index=True)
|
||||
control = [0, 1, 2, 3, 5]
|
||||
assert_equal(sorted(test[-1]), control)
|
||||
assert_equal(test[0], a[test[-1]])
|
||||
|
||||
test = find_duplicates(a, key='B', return_index=True)
|
||||
control = [0, 1, 2, 4]
|
||||
assert_equal(sorted(test[-1]), control)
|
||||
assert_equal(test[0], a[test[-1]])
|
||||
|
||||
test = find_duplicates(a, key='BA', return_index=True)
|
||||
control = [0, 1, 2, 4]
|
||||
assert_equal(sorted(test[-1]), control)
|
||||
assert_equal(test[0], a[test[-1]])
|
||||
|
||||
test = find_duplicates(a, key='BB', return_index=True)
|
||||
control = [0, 1, 2, 3, 4]
|
||||
assert_equal(sorted(test[-1]), control)
|
||||
assert_equal(test[0], a[test[-1]])
|
||||
|
||||
def test_find_duplicates_ignoremask(self):
|
||||
# Test the ignoremask option of find_duplicates
|
||||
ndtype = [('a', int)]
|
||||
a = ma.array([1, 1, 1, 2, 2, 3, 3],
|
||||
mask=[0, 0, 1, 0, 0, 0, 1]).view(ndtype)
|
||||
test = find_duplicates(a, ignoremask=True, return_index=True)
|
||||
control = [0, 1, 3, 4]
|
||||
assert_equal(sorted(test[-1]), control)
|
||||
assert_equal(test[0], a[test[-1]])
|
||||
|
||||
test = find_duplicates(a, ignoremask=False, return_index=True)
|
||||
control = [0, 1, 2, 3, 4, 6]
|
||||
assert_equal(sorted(test[-1]), control)
|
||||
assert_equal(test[0], a[test[-1]])
|
||||
|
||||
def test_repack_fields(self):
|
||||
dt = np.dtype('u1,f4,i8', align=True)
|
||||
a = np.zeros(2, dtype=dt)
|
||||
|
||||
assert_equal(repack_fields(dt), np.dtype('u1,f4,i8'))
|
||||
assert_equal(repack_fields(a).itemsize, 13)
|
||||
assert_equal(repack_fields(repack_fields(dt), align=True), dt)
|
||||
|
||||
# make sure type is preserved
|
||||
dt = np.dtype((np.record, dt))
|
||||
assert_(repack_fields(dt).type is np.record)
|
||||
|
||||
def test_structured_to_unstructured(self):
|
||||
a = np.zeros(4, dtype=[('a', 'i4'), ('b', 'f4,u2'), ('c', 'f4', 2)])
|
||||
out = structured_to_unstructured(a)
|
||||
assert_equal(out, np.zeros((4,5), dtype='f8'))
|
||||
|
||||
b = np.array([(1, 2, 5), (4, 5, 7), (7, 8 ,11), (10, 11, 12)],
|
||||
dtype=[('x', 'i4'), ('y', 'f4'), ('z', 'f8')])
|
||||
out = np.mean(structured_to_unstructured(b[['x', 'z']]), axis=-1)
|
||||
assert_equal(out, np.array([ 3. , 5.5, 9. , 11. ]))
|
||||
|
||||
c = np.arange(20).reshape((4,5))
|
||||
out = unstructured_to_structured(c, a.dtype)
|
||||
want = np.array([( 0, ( 1., 2), [ 3., 4.]),
|
||||
( 5, ( 6., 7), [ 8., 9.]),
|
||||
(10, (11., 12), [13., 14.]),
|
||||
(15, (16., 17), [18., 19.])],
|
||||
dtype=[('a', 'i4'),
|
||||
('b', [('f0', 'f4'), ('f1', 'u2')]),
|
||||
('c', 'f4', (2,))])
|
||||
assert_equal(out, want)
|
||||
|
||||
d = np.array([(1, 2, 5), (4, 5, 7), (7, 8 ,11), (10, 11, 12)],
|
||||
dtype=[('x', 'i4'), ('y', 'f4'), ('z', 'f8')])
|
||||
assert_equal(apply_along_fields(np.mean, d),
|
||||
np.array([ 8.0/3, 16.0/3, 26.0/3, 11. ]))
|
||||
assert_equal(apply_along_fields(np.mean, d[['x', 'z']]),
|
||||
np.array([ 3. , 5.5, 9. , 11. ]))
|
||||
|
||||
# check that for uniform field dtypes we get a view, not a copy:
|
||||
d = np.array([(1, 2, 5), (4, 5, 7), (7, 8 ,11), (10, 11, 12)],
|
||||
dtype=[('x', 'i4'), ('y', 'i4'), ('z', 'i4')])
|
||||
dd = structured_to_unstructured(d)
|
||||
ddd = unstructured_to_structured(dd, d.dtype)
|
||||
assert_(dd.base is d)
|
||||
assert_(ddd.base is d)
|
||||
|
||||
# test that nested fields with identical names don't break anything
|
||||
point = np.dtype([('x', int), ('y', int)])
|
||||
triangle = np.dtype([('a', point), ('b', point), ('c', point)])
|
||||
arr = np.zeros(10, triangle)
|
||||
res = structured_to_unstructured(arr, dtype=int)
|
||||
assert_equal(res, np.zeros((10, 6), dtype=int))
|
||||
|
||||
|
||||
def test_field_assignment_by_name(self):
|
||||
a = np.ones(2, dtype=[('a', 'i4'), ('b', 'f8'), ('c', 'u1')])
|
||||
newdt = [('b', 'f4'), ('c', 'u1')]
|
||||
|
||||
assert_equal(require_fields(a, newdt), np.ones(2, newdt))
|
||||
|
||||
b = np.array([(1,2), (3,4)], dtype=newdt)
|
||||
assign_fields_by_name(a, b, zero_unassigned=False)
|
||||
assert_equal(a, np.array([(1,1,2),(1,3,4)], dtype=a.dtype))
|
||||
assign_fields_by_name(a, b)
|
||||
assert_equal(a, np.array([(0,1,2),(0,3,4)], dtype=a.dtype))
|
||||
|
||||
# test nested fields
|
||||
a = np.ones(2, dtype=[('a', [('b', 'f8'), ('c', 'u1')])])
|
||||
newdt = [('a', [('c', 'u1')])]
|
||||
assert_equal(require_fields(a, newdt), np.ones(2, newdt))
|
||||
b = np.array([((2,),), ((3,),)], dtype=newdt)
|
||||
assign_fields_by_name(a, b, zero_unassigned=False)
|
||||
assert_equal(a, np.array([((1,2),), ((1,3),)], dtype=a.dtype))
|
||||
assign_fields_by_name(a, b)
|
||||
assert_equal(a, np.array([((0,2),), ((0,3),)], dtype=a.dtype))
|
||||
|
||||
# test unstructured code path for 0d arrays
|
||||
a, b = np.array(3), np.array(0)
|
||||
assign_fields_by_name(b, a)
|
||||
assert_equal(b[()], 3)
|
||||
|
||||
|
||||
class TestRecursiveFillFields(object):
|
||||
# Test recursive_fill_fields.
|
||||
def test_simple_flexible(self):
|
||||
# Test recursive_fill_fields on flexible-array
|
||||
a = np.array([(1, 10.), (2, 20.)], dtype=[('A', int), ('B', float)])
|
||||
b = np.zeros((3,), dtype=a.dtype)
|
||||
test = recursive_fill_fields(a, b)
|
||||
control = np.array([(1, 10.), (2, 20.), (0, 0.)],
|
||||
dtype=[('A', int), ('B', float)])
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_masked_flexible(self):
|
||||
# Test recursive_fill_fields on masked flexible-array
|
||||
a = ma.array([(1, 10.), (2, 20.)], mask=[(0, 1), (1, 0)],
|
||||
dtype=[('A', int), ('B', float)])
|
||||
b = ma.zeros((3,), dtype=a.dtype)
|
||||
test = recursive_fill_fields(a, b)
|
||||
control = ma.array([(1, 10.), (2, 20.), (0, 0.)],
|
||||
mask=[(0, 1), (1, 0), (0, 0)],
|
||||
dtype=[('A', int), ('B', float)])
|
||||
assert_equal(test, control)
|
||||
|
||||
|
||||
class TestMergeArrays(object):
|
||||
# Test merge_arrays
|
||||
|
||||
def setup(self):
|
||||
x = np.array([1, 2, ])
|
||||
y = np.array([10, 20, 30])
|
||||
z = np.array(
|
||||
[('A', 1.), ('B', 2.)], dtype=[('A', '|S3'), ('B', float)])
|
||||
w = np.array(
|
||||
[(1, (2, 3.0)), (4, (5, 6.0))],
|
||||
dtype=[('a', int), ('b', [('ba', float), ('bb', int)])])
|
||||
self.data = (w, x, y, z)
|
||||
|
||||
def test_solo(self):
|
||||
# Test merge_arrays on a single array.
|
||||
(_, x, _, z) = self.data
|
||||
|
||||
test = merge_arrays(x)
|
||||
control = np.array([(1,), (2,)], dtype=[('f0', int)])
|
||||
assert_equal(test, control)
|
||||
test = merge_arrays((x,))
|
||||
assert_equal(test, control)
|
||||
|
||||
test = merge_arrays(z, flatten=False)
|
||||
assert_equal(test, z)
|
||||
test = merge_arrays(z, flatten=True)
|
||||
assert_equal(test, z)
|
||||
|
||||
def test_solo_w_flatten(self):
|
||||
# Test merge_arrays on a single array w & w/o flattening
|
||||
w = self.data[0]
|
||||
test = merge_arrays(w, flatten=False)
|
||||
assert_equal(test, w)
|
||||
|
||||
test = merge_arrays(w, flatten=True)
|
||||
control = np.array([(1, 2, 3.0), (4, 5, 6.0)],
|
||||
dtype=[('a', int), ('ba', float), ('bb', int)])
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_standard(self):
|
||||
# Test standard & standard
|
||||
# Test merge arrays
|
||||
(_, x, y, _) = self.data
|
||||
test = merge_arrays((x, y), usemask=False)
|
||||
control = np.array([(1, 10), (2, 20), (-1, 30)],
|
||||
dtype=[('f0', int), ('f1', int)])
|
||||
assert_equal(test, control)
|
||||
|
||||
test = merge_arrays((x, y), usemask=True)
|
||||
control = ma.array([(1, 10), (2, 20), (-1, 30)],
|
||||
mask=[(0, 0), (0, 0), (1, 0)],
|
||||
dtype=[('f0', int), ('f1', int)])
|
||||
assert_equal(test, control)
|
||||
assert_equal(test.mask, control.mask)
|
||||
|
||||
def test_flatten(self):
|
||||
# Test standard & flexible
|
||||
(_, x, _, z) = self.data
|
||||
test = merge_arrays((x, z), flatten=True)
|
||||
control = np.array([(1, 'A', 1.), (2, 'B', 2.)],
|
||||
dtype=[('f0', int), ('A', '|S3'), ('B', float)])
|
||||
assert_equal(test, control)
|
||||
|
||||
test = merge_arrays((x, z), flatten=False)
|
||||
control = np.array([(1, ('A', 1.)), (2, ('B', 2.))],
|
||||
dtype=[('f0', int),
|
||||
('f1', [('A', '|S3'), ('B', float)])])
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_flatten_wflexible(self):
|
||||
# Test flatten standard & nested
|
||||
(w, x, _, _) = self.data
|
||||
test = merge_arrays((x, w), flatten=True)
|
||||
control = np.array([(1, 1, 2, 3.0), (2, 4, 5, 6.0)],
|
||||
dtype=[('f0', int),
|
||||
('a', int), ('ba', float), ('bb', int)])
|
||||
assert_equal(test, control)
|
||||
|
||||
test = merge_arrays((x, w), flatten=False)
|
||||
controldtype = [('f0', int),
|
||||
('f1', [('a', int),
|
||||
('b', [('ba', float), ('bb', int)])])]
|
||||
control = np.array([(1., (1, (2, 3.0))), (2, (4, (5, 6.0)))],
|
||||
dtype=controldtype)
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_wmasked_arrays(self):
|
||||
# Test merge_arrays masked arrays
|
||||
(_, x, _, _) = self.data
|
||||
mx = ma.array([1, 2, 3], mask=[1, 0, 0])
|
||||
test = merge_arrays((x, mx), usemask=True)
|
||||
control = ma.array([(1, 1), (2, 2), (-1, 3)],
|
||||
mask=[(0, 1), (0, 0), (1, 0)],
|
||||
dtype=[('f0', int), ('f1', int)])
|
||||
assert_equal(test, control)
|
||||
test = merge_arrays((x, mx), usemask=True, asrecarray=True)
|
||||
assert_equal(test, control)
|
||||
assert_(isinstance(test, MaskedRecords))
|
||||
|
||||
def test_w_singlefield(self):
|
||||
# Test single field
|
||||
test = merge_arrays((np.array([1, 2]).view([('a', int)]),
|
||||
np.array([10., 20., 30.])),)
|
||||
control = ma.array([(1, 10.), (2, 20.), (-1, 30.)],
|
||||
mask=[(0, 0), (0, 0), (1, 0)],
|
||||
dtype=[('a', int), ('f1', float)])
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_w_shorter_flex(self):
|
||||
# Test merge_arrays w/ a shorter flexndarray.
|
||||
z = self.data[-1]
|
||||
|
||||
# Fixme, this test looks incomplete and broken
|
||||
#test = merge_arrays((z, np.array([10, 20, 30]).view([('C', int)])))
|
||||
#control = np.array([('A', 1., 10), ('B', 2., 20), ('-1', -1, 20)],
|
||||
# dtype=[('A', '|S3'), ('B', float), ('C', int)])
|
||||
#assert_equal(test, control)
|
||||
|
||||
# Hack to avoid pyflakes warnings about unused variables
|
||||
merge_arrays((z, np.array([10, 20, 30]).view([('C', int)])))
|
||||
np.array([('A', 1., 10), ('B', 2., 20), ('-1', -1, 20)],
|
||||
dtype=[('A', '|S3'), ('B', float), ('C', int)])
|
||||
|
||||
def test_singlerecord(self):
|
||||
(_, x, y, z) = self.data
|
||||
test = merge_arrays((x[0], y[0], z[0]), usemask=False)
|
||||
control = np.array([(1, 10, ('A', 1))],
|
||||
dtype=[('f0', int),
|
||||
('f1', int),
|
||||
('f2', [('A', '|S3'), ('B', float)])])
|
||||
assert_equal(test, control)
|
||||
|
||||
|
||||
class TestAppendFields(object):
|
||||
# Test append_fields
|
||||
|
||||
def setup(self):
|
||||
x = np.array([1, 2, ])
|
||||
y = np.array([10, 20, 30])
|
||||
z = np.array(
|
||||
[('A', 1.), ('B', 2.)], dtype=[('A', '|S3'), ('B', float)])
|
||||
w = np.array([(1, (2, 3.0)), (4, (5, 6.0))],
|
||||
dtype=[('a', int), ('b', [('ba', float), ('bb', int)])])
|
||||
self.data = (w, x, y, z)
|
||||
|
||||
def test_append_single(self):
|
||||
# Test simple case
|
||||
(_, x, _, _) = self.data
|
||||
test = append_fields(x, 'A', data=[10, 20, 30])
|
||||
control = ma.array([(1, 10), (2, 20), (-1, 30)],
|
||||
mask=[(0, 0), (0, 0), (1, 0)],
|
||||
dtype=[('f0', int), ('A', int)],)
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_append_double(self):
|
||||
# Test simple case
|
||||
(_, x, _, _) = self.data
|
||||
test = append_fields(x, ('A', 'B'), data=[[10, 20, 30], [100, 200]])
|
||||
control = ma.array([(1, 10, 100), (2, 20, 200), (-1, 30, -1)],
|
||||
mask=[(0, 0, 0), (0, 0, 0), (1, 0, 1)],
|
||||
dtype=[('f0', int), ('A', int), ('B', int)],)
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_append_on_flex(self):
|
||||
# Test append_fields on flexible type arrays
|
||||
z = self.data[-1]
|
||||
test = append_fields(z, 'C', data=[10, 20, 30])
|
||||
control = ma.array([('A', 1., 10), ('B', 2., 20), (-1, -1., 30)],
|
||||
mask=[(0, 0, 0), (0, 0, 0), (1, 1, 0)],
|
||||
dtype=[('A', '|S3'), ('B', float), ('C', int)],)
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_append_on_nested(self):
|
||||
# Test append_fields on nested fields
|
||||
w = self.data[0]
|
||||
test = append_fields(w, 'C', data=[10, 20, 30])
|
||||
control = ma.array([(1, (2, 3.0), 10),
|
||||
(4, (5, 6.0), 20),
|
||||
(-1, (-1, -1.), 30)],
|
||||
mask=[(
|
||||
0, (0, 0), 0), (0, (0, 0), 0), (1, (1, 1), 0)],
|
||||
dtype=[('a', int),
|
||||
('b', [('ba', float), ('bb', int)]),
|
||||
('C', int)],)
|
||||
assert_equal(test, control)
|
||||
|
||||
|
||||
class TestStackArrays(object):
|
||||
# Test stack_arrays
|
||||
def setup(self):
|
||||
x = np.array([1, 2, ])
|
||||
y = np.array([10, 20, 30])
|
||||
z = np.array(
|
||||
[('A', 1.), ('B', 2.)], dtype=[('A', '|S3'), ('B', float)])
|
||||
w = np.array([(1, (2, 3.0)), (4, (5, 6.0))],
|
||||
dtype=[('a', int), ('b', [('ba', float), ('bb', int)])])
|
||||
self.data = (w, x, y, z)
|
||||
|
||||
def test_solo(self):
|
||||
# Test stack_arrays on single arrays
|
||||
(_, x, _, _) = self.data
|
||||
test = stack_arrays((x,))
|
||||
assert_equal(test, x)
|
||||
assert_(test is x)
|
||||
|
||||
test = stack_arrays(x)
|
||||
assert_equal(test, x)
|
||||
assert_(test is x)
|
||||
|
||||
def test_unnamed_fields(self):
|
||||
# Tests combinations of arrays w/o named fields
|
||||
(_, x, y, _) = self.data
|
||||
|
||||
test = stack_arrays((x, x), usemask=False)
|
||||
control = np.array([1, 2, 1, 2])
|
||||
assert_equal(test, control)
|
||||
|
||||
test = stack_arrays((x, y), usemask=False)
|
||||
control = np.array([1, 2, 10, 20, 30])
|
||||
assert_equal(test, control)
|
||||
|
||||
test = stack_arrays((y, x), usemask=False)
|
||||
control = np.array([10, 20, 30, 1, 2])
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_unnamed_and_named_fields(self):
|
||||
# Test combination of arrays w/ & w/o named fields
|
||||
(_, x, _, z) = self.data
|
||||
|
||||
test = stack_arrays((x, z))
|
||||
control = ma.array([(1, -1, -1), (2, -1, -1),
|
||||
(-1, 'A', 1), (-1, 'B', 2)],
|
||||
mask=[(0, 1, 1), (0, 1, 1),
|
||||
(1, 0, 0), (1, 0, 0)],
|
||||
dtype=[('f0', int), ('A', '|S3'), ('B', float)])
|
||||
assert_equal(test, control)
|
||||
assert_equal(test.mask, control.mask)
|
||||
|
||||
test = stack_arrays((z, x))
|
||||
control = ma.array([('A', 1, -1), ('B', 2, -1),
|
||||
(-1, -1, 1), (-1, -1, 2), ],
|
||||
mask=[(0, 0, 1), (0, 0, 1),
|
||||
(1, 1, 0), (1, 1, 0)],
|
||||
dtype=[('A', '|S3'), ('B', float), ('f2', int)])
|
||||
assert_equal(test, control)
|
||||
assert_equal(test.mask, control.mask)
|
||||
|
||||
test = stack_arrays((z, z, x))
|
||||
control = ma.array([('A', 1, -1), ('B', 2, -1),
|
||||
('A', 1, -1), ('B', 2, -1),
|
||||
(-1, -1, 1), (-1, -1, 2), ],
|
||||
mask=[(0, 0, 1), (0, 0, 1),
|
||||
(0, 0, 1), (0, 0, 1),
|
||||
(1, 1, 0), (1, 1, 0)],
|
||||
dtype=[('A', '|S3'), ('B', float), ('f2', int)])
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_matching_named_fields(self):
|
||||
# Test combination of arrays w/ matching field names
|
||||
(_, x, _, z) = self.data
|
||||
zz = np.array([('a', 10., 100.), ('b', 20., 200.), ('c', 30., 300.)],
|
||||
dtype=[('A', '|S3'), ('B', float), ('C', float)])
|
||||
test = stack_arrays((z, zz))
|
||||
control = ma.array([('A', 1, -1), ('B', 2, -1),
|
||||
(
|
||||
'a', 10., 100.), ('b', 20., 200.), ('c', 30., 300.)],
|
||||
dtype=[('A', '|S3'), ('B', float), ('C', float)],
|
||||
mask=[(0, 0, 1), (0, 0, 1),
|
||||
(0, 0, 0), (0, 0, 0), (0, 0, 0)])
|
||||
assert_equal(test, control)
|
||||
assert_equal(test.mask, control.mask)
|
||||
|
||||
test = stack_arrays((z, zz, x))
|
||||
ndtype = [('A', '|S3'), ('B', float), ('C', float), ('f3', int)]
|
||||
control = ma.array([('A', 1, -1, -1), ('B', 2, -1, -1),
|
||||
('a', 10., 100., -1), ('b', 20., 200., -1),
|
||||
('c', 30., 300., -1),
|
||||
(-1, -1, -1, 1), (-1, -1, -1, 2)],
|
||||
dtype=ndtype,
|
||||
mask=[(0, 0, 1, 1), (0, 0, 1, 1),
|
||||
(0, 0, 0, 1), (0, 0, 0, 1), (0, 0, 0, 1),
|
||||
(1, 1, 1, 0), (1, 1, 1, 0)])
|
||||
assert_equal(test, control)
|
||||
assert_equal(test.mask, control.mask)
|
||||
|
||||
def test_defaults(self):
|
||||
# Test defaults: no exception raised if keys of defaults are not fields.
|
||||
(_, _, _, z) = self.data
|
||||
zz = np.array([('a', 10., 100.), ('b', 20., 200.), ('c', 30., 300.)],
|
||||
dtype=[('A', '|S3'), ('B', float), ('C', float)])
|
||||
defaults = {'A': '???', 'B': -999., 'C': -9999., 'D': -99999.}
|
||||
test = stack_arrays((z, zz), defaults=defaults)
|
||||
control = ma.array([('A', 1, -9999.), ('B', 2, -9999.),
|
||||
(
|
||||
'a', 10., 100.), ('b', 20., 200.), ('c', 30., 300.)],
|
||||
dtype=[('A', '|S3'), ('B', float), ('C', float)],
|
||||
mask=[(0, 0, 1), (0, 0, 1),
|
||||
(0, 0, 0), (0, 0, 0), (0, 0, 0)])
|
||||
assert_equal(test, control)
|
||||
assert_equal(test.data, control.data)
|
||||
assert_equal(test.mask, control.mask)
|
||||
|
||||
def test_autoconversion(self):
|
||||
# Tests autoconversion
|
||||
adtype = [('A', int), ('B', bool), ('C', float)]
|
||||
a = ma.array([(1, 2, 3)], mask=[(0, 1, 0)], dtype=adtype)
|
||||
bdtype = [('A', int), ('B', float), ('C', float)]
|
||||
b = ma.array([(4, 5, 6)], dtype=bdtype)
|
||||
control = ma.array([(1, 2, 3), (4, 5, 6)], mask=[(0, 1, 0), (0, 0, 0)],
|
||||
dtype=bdtype)
|
||||
test = stack_arrays((a, b), autoconvert=True)
|
||||
assert_equal(test, control)
|
||||
assert_equal(test.mask, control.mask)
|
||||
with assert_raises(TypeError):
|
||||
stack_arrays((a, b), autoconvert=False)
|
||||
|
||||
def test_checktitles(self):
|
||||
# Test using titles in the field names
|
||||
adtype = [(('a', 'A'), int), (('b', 'B'), bool), (('c', 'C'), float)]
|
||||
a = ma.array([(1, 2, 3)], mask=[(0, 1, 0)], dtype=adtype)
|
||||
bdtype = [(('a', 'A'), int), (('b', 'B'), bool), (('c', 'C'), float)]
|
||||
b = ma.array([(4, 5, 6)], dtype=bdtype)
|
||||
test = stack_arrays((a, b))
|
||||
control = ma.array([(1, 2, 3), (4, 5, 6)], mask=[(0, 1, 0), (0, 0, 0)],
|
||||
dtype=bdtype)
|
||||
assert_equal(test, control)
|
||||
assert_equal(test.mask, control.mask)
|
||||
|
||||
def test_subdtype(self):
|
||||
z = np.array([
|
||||
('A', 1), ('B', 2)
|
||||
], dtype=[('A', '|S3'), ('B', float, (1,))])
|
||||
zz = np.array([
|
||||
('a', [10.], 100.), ('b', [20.], 200.), ('c', [30.], 300.)
|
||||
], dtype=[('A', '|S3'), ('B', float, (1,)), ('C', float)])
|
||||
|
||||
res = stack_arrays((z, zz))
|
||||
expected = ma.array(
|
||||
data=[
|
||||
(b'A', [1.0], 0),
|
||||
(b'B', [2.0], 0),
|
||||
(b'a', [10.0], 100.0),
|
||||
(b'b', [20.0], 200.0),
|
||||
(b'c', [30.0], 300.0)],
|
||||
mask=[
|
||||
(False, [False], True),
|
||||
(False, [False], True),
|
||||
(False, [False], False),
|
||||
(False, [False], False),
|
||||
(False, [False], False)
|
||||
],
|
||||
dtype=zz.dtype
|
||||
)
|
||||
assert_equal(res.dtype, expected.dtype)
|
||||
assert_equal(res, expected)
|
||||
assert_equal(res.mask, expected.mask)
|
||||
|
||||
|
||||
class TestJoinBy(object):
|
||||
def setup(self):
|
||||
self.a = np.array(list(zip(np.arange(10), np.arange(50, 60),
|
||||
np.arange(100, 110))),
|
||||
dtype=[('a', int), ('b', int), ('c', int)])
|
||||
self.b = np.array(list(zip(np.arange(5, 15), np.arange(65, 75),
|
||||
np.arange(100, 110))),
|
||||
dtype=[('a', int), ('b', int), ('d', int)])
|
||||
|
||||
def test_inner_join(self):
|
||||
# Basic test of join_by
|
||||
a, b = self.a, self.b
|
||||
|
||||
test = join_by('a', a, b, jointype='inner')
|
||||
control = np.array([(5, 55, 65, 105, 100), (6, 56, 66, 106, 101),
|
||||
(7, 57, 67, 107, 102), (8, 58, 68, 108, 103),
|
||||
(9, 59, 69, 109, 104)],
|
||||
dtype=[('a', int), ('b1', int), ('b2', int),
|
||||
('c', int), ('d', int)])
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_join(self):
|
||||
a, b = self.a, self.b
|
||||
|
||||
# Fixme, this test is broken
|
||||
#test = join_by(('a', 'b'), a, b)
|
||||
#control = np.array([(5, 55, 105, 100), (6, 56, 106, 101),
|
||||
# (7, 57, 107, 102), (8, 58, 108, 103),
|
||||
# (9, 59, 109, 104)],
|
||||
# dtype=[('a', int), ('b', int),
|
||||
# ('c', int), ('d', int)])
|
||||
#assert_equal(test, control)
|
||||
|
||||
# Hack to avoid pyflakes unused variable warnings
|
||||
join_by(('a', 'b'), a, b)
|
||||
np.array([(5, 55, 105, 100), (6, 56, 106, 101),
|
||||
(7, 57, 107, 102), (8, 58, 108, 103),
|
||||
(9, 59, 109, 104)],
|
||||
dtype=[('a', int), ('b', int),
|
||||
('c', int), ('d', int)])
|
||||
|
||||
def test_join_subdtype(self):
|
||||
# tests the bug in https://stackoverflow.com/q/44769632/102441
|
||||
from numpy.lib import recfunctions as rfn
|
||||
foo = np.array([(1,)],
|
||||
dtype=[('key', int)])
|
||||
bar = np.array([(1, np.array([1,2,3]))],
|
||||
dtype=[('key', int), ('value', 'uint16', 3)])
|
||||
res = join_by('key', foo, bar)
|
||||
assert_equal(res, bar.view(ma.MaskedArray))
|
||||
|
||||
def test_outer_join(self):
|
||||
a, b = self.a, self.b
|
||||
|
||||
test = join_by(('a', 'b'), a, b, 'outer')
|
||||
control = ma.array([(0, 50, 100, -1), (1, 51, 101, -1),
|
||||
(2, 52, 102, -1), (3, 53, 103, -1),
|
||||
(4, 54, 104, -1), (5, 55, 105, -1),
|
||||
(5, 65, -1, 100), (6, 56, 106, -1),
|
||||
(6, 66, -1, 101), (7, 57, 107, -1),
|
||||
(7, 67, -1, 102), (8, 58, 108, -1),
|
||||
(8, 68, -1, 103), (9, 59, 109, -1),
|
||||
(9, 69, -1, 104), (10, 70, -1, 105),
|
||||
(11, 71, -1, 106), (12, 72, -1, 107),
|
||||
(13, 73, -1, 108), (14, 74, -1, 109)],
|
||||
mask=[(0, 0, 0, 1), (0, 0, 0, 1),
|
||||
(0, 0, 0, 1), (0, 0, 0, 1),
|
||||
(0, 0, 0, 1), (0, 0, 0, 1),
|
||||
(0, 0, 1, 0), (0, 0, 0, 1),
|
||||
(0, 0, 1, 0), (0, 0, 0, 1),
|
||||
(0, 0, 1, 0), (0, 0, 0, 1),
|
||||
(0, 0, 1, 0), (0, 0, 0, 1),
|
||||
(0, 0, 1, 0), (0, 0, 1, 0),
|
||||
(0, 0, 1, 0), (0, 0, 1, 0),
|
||||
(0, 0, 1, 0), (0, 0, 1, 0)],
|
||||
dtype=[('a', int), ('b', int),
|
||||
('c', int), ('d', int)])
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_leftouter_join(self):
|
||||
a, b = self.a, self.b
|
||||
|
||||
test = join_by(('a', 'b'), a, b, 'leftouter')
|
||||
control = ma.array([(0, 50, 100, -1), (1, 51, 101, -1),
|
||||
(2, 52, 102, -1), (3, 53, 103, -1),
|
||||
(4, 54, 104, -1), (5, 55, 105, -1),
|
||||
(6, 56, 106, -1), (7, 57, 107, -1),
|
||||
(8, 58, 108, -1), (9, 59, 109, -1)],
|
||||
mask=[(0, 0, 0, 1), (0, 0, 0, 1),
|
||||
(0, 0, 0, 1), (0, 0, 0, 1),
|
||||
(0, 0, 0, 1), (0, 0, 0, 1),
|
||||
(0, 0, 0, 1), (0, 0, 0, 1),
|
||||
(0, 0, 0, 1), (0, 0, 0, 1)],
|
||||
dtype=[('a', int), ('b', int), ('c', int), ('d', int)])
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_different_field_order(self):
|
||||
# gh-8940
|
||||
a = np.zeros(3, dtype=[('a', 'i4'), ('b', 'f4'), ('c', 'u1')])
|
||||
b = np.ones(3, dtype=[('c', 'u1'), ('b', 'f4'), ('a', 'i4')])
|
||||
# this should not give a FutureWarning:
|
||||
j = join_by(['c', 'b'], a, b, jointype='inner', usemask=False)
|
||||
assert_equal(j.dtype.names, ['b', 'c', 'a1', 'a2'])
|
||||
|
||||
def test_duplicate_keys(self):
|
||||
a = np.zeros(3, dtype=[('a', 'i4'), ('b', 'f4'), ('c', 'u1')])
|
||||
b = np.ones(3, dtype=[('c', 'u1'), ('b', 'f4'), ('a', 'i4')])
|
||||
assert_raises(ValueError, join_by, ['a', 'b', 'b'], a, b)
|
||||
|
||||
@pytest.mark.xfail(reason="See comment at gh-9343")
|
||||
def test_same_name_different_dtypes_key(self):
|
||||
a_dtype = np.dtype([('key', 'S5'), ('value', '<f4')])
|
||||
b_dtype = np.dtype([('key', 'S10'), ('value', '<f4')])
|
||||
expected_dtype = np.dtype([
|
||||
('key', 'S10'), ('value1', '<f4'), ('value2', '<f4')])
|
||||
|
||||
a = np.array([('Sarah', 8.0), ('John', 6.0)], dtype=a_dtype)
|
||||
b = np.array([('Sarah', 10.0), ('John', 7.0)], dtype=b_dtype)
|
||||
res = join_by('key', a, b)
|
||||
|
||||
assert_equal(res.dtype, expected_dtype)
|
||||
|
||||
def test_same_name_different_dtypes(self):
|
||||
# gh-9338
|
||||
a_dtype = np.dtype([('key', 'S10'), ('value', '<f4')])
|
||||
b_dtype = np.dtype([('key', 'S10'), ('value', '<f8')])
|
||||
expected_dtype = np.dtype([
|
||||
('key', '|S10'), ('value1', '<f4'), ('value2', '<f8')])
|
||||
|
||||
a = np.array([('Sarah', 8.0), ('John', 6.0)], dtype=a_dtype)
|
||||
b = np.array([('Sarah', 10.0), ('John', 7.0)], dtype=b_dtype)
|
||||
res = join_by('key', a, b)
|
||||
|
||||
assert_equal(res.dtype, expected_dtype)
|
||||
|
||||
def test_subarray_key(self):
|
||||
a_dtype = np.dtype([('pos', int, 3), ('f', '<f4')])
|
||||
a = np.array([([1, 1, 1], np.pi), ([1, 2, 3], 0.0)], dtype=a_dtype)
|
||||
|
||||
b_dtype = np.dtype([('pos', int, 3), ('g', '<f4')])
|
||||
b = np.array([([1, 1, 1], 3), ([3, 2, 1], 0.0)], dtype=b_dtype)
|
||||
|
||||
expected_dtype = np.dtype([('pos', int, 3), ('f', '<f4'), ('g', '<f4')])
|
||||
expected = np.array([([1, 1, 1], np.pi, 3)], dtype=expected_dtype)
|
||||
|
||||
res = join_by('pos', a, b)
|
||||
assert_equal(res.dtype, expected_dtype)
|
||||
assert_equal(res, expected)
|
||||
|
||||
def test_padded_dtype(self):
|
||||
dt = np.dtype('i1,f4', align=True)
|
||||
dt.names = ('k', 'v')
|
||||
assert_(len(dt.descr), 3) # padding field is inserted
|
||||
|
||||
a = np.array([(1, 3), (3, 2)], dt)
|
||||
b = np.array([(1, 1), (2, 2)], dt)
|
||||
res = join_by('k', a, b)
|
||||
|
||||
# no padding fields remain
|
||||
expected_dtype = np.dtype([
|
||||
('k', 'i1'), ('v1', 'f4'), ('v2', 'f4')
|
||||
])
|
||||
|
||||
assert_equal(res.dtype, expected_dtype)
|
||||
|
||||
|
||||
class TestJoinBy2(object):
|
||||
@classmethod
|
||||
def setup(cls):
|
||||
cls.a = np.array(list(zip(np.arange(10), np.arange(50, 60),
|
||||
np.arange(100, 110))),
|
||||
dtype=[('a', int), ('b', int), ('c', int)])
|
||||
cls.b = np.array(list(zip(np.arange(10), np.arange(65, 75),
|
||||
np.arange(100, 110))),
|
||||
dtype=[('a', int), ('b', int), ('d', int)])
|
||||
|
||||
def test_no_r1postfix(self):
|
||||
# Basic test of join_by no_r1postfix
|
||||
a, b = self.a, self.b
|
||||
|
||||
test = join_by(
|
||||
'a', a, b, r1postfix='', r2postfix='2', jointype='inner')
|
||||
control = np.array([(0, 50, 65, 100, 100), (1, 51, 66, 101, 101),
|
||||
(2, 52, 67, 102, 102), (3, 53, 68, 103, 103),
|
||||
(4, 54, 69, 104, 104), (5, 55, 70, 105, 105),
|
||||
(6, 56, 71, 106, 106), (7, 57, 72, 107, 107),
|
||||
(8, 58, 73, 108, 108), (9, 59, 74, 109, 109)],
|
||||
dtype=[('a', int), ('b', int), ('b2', int),
|
||||
('c', int), ('d', int)])
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_no_postfix(self):
|
||||
assert_raises(ValueError, join_by, 'a', self.a, self.b,
|
||||
r1postfix='', r2postfix='')
|
||||
|
||||
def test_no_r2postfix(self):
|
||||
# Basic test of join_by no_r2postfix
|
||||
a, b = self.a, self.b
|
||||
|
||||
test = join_by(
|
||||
'a', a, b, r1postfix='1', r2postfix='', jointype='inner')
|
||||
control = np.array([(0, 50, 65, 100, 100), (1, 51, 66, 101, 101),
|
||||
(2, 52, 67, 102, 102), (3, 53, 68, 103, 103),
|
||||
(4, 54, 69, 104, 104), (5, 55, 70, 105, 105),
|
||||
(6, 56, 71, 106, 106), (7, 57, 72, 107, 107),
|
||||
(8, 58, 73, 108, 108), (9, 59, 74, 109, 109)],
|
||||
dtype=[('a', int), ('b1', int), ('b', int),
|
||||
('c', int), ('d', int)])
|
||||
assert_equal(test, control)
|
||||
|
||||
def test_two_keys_two_vars(self):
|
||||
a = np.array(list(zip(np.tile([10, 11], 5), np.repeat(np.arange(5), 2),
|
||||
np.arange(50, 60), np.arange(10, 20))),
|
||||
dtype=[('k', int), ('a', int), ('b', int), ('c', int)])
|
||||
|
||||
b = np.array(list(zip(np.tile([10, 11], 5), np.repeat(np.arange(5), 2),
|
||||
np.arange(65, 75), np.arange(0, 10))),
|
||||
dtype=[('k', int), ('a', int), ('b', int), ('c', int)])
|
||||
|
||||
control = np.array([(10, 0, 50, 65, 10, 0), (11, 0, 51, 66, 11, 1),
|
||||
(10, 1, 52, 67, 12, 2), (11, 1, 53, 68, 13, 3),
|
||||
(10, 2, 54, 69, 14, 4), (11, 2, 55, 70, 15, 5),
|
||||
(10, 3, 56, 71, 16, 6), (11, 3, 57, 72, 17, 7),
|
||||
(10, 4, 58, 73, 18, 8), (11, 4, 59, 74, 19, 9)],
|
||||
dtype=[('k', int), ('a', int), ('b1', int),
|
||||
('b2', int), ('c1', int), ('c2', int)])
|
||||
test = join_by(
|
||||
['a', 'k'], a, b, r1postfix='1', r2postfix='2', jointype='inner')
|
||||
assert_equal(test.dtype, control.dtype)
|
||||
assert_equal(test, control)
|
||||
|
||||
class TestAppendFieldsObj(object):
|
||||
"""
|
||||
Test append_fields with arrays containing objects
|
||||
"""
|
||||
# https://github.com/numpy/numpy/issues/2346
|
||||
|
||||
def setup(self):
|
||||
from datetime import date
|
||||
self.data = dict(obj=date(2000, 1, 1))
|
||||
|
||||
def test_append_to_objects(self):
|
||||
"Test append_fields when the base array contains objects"
|
||||
obj = self.data['obj']
|
||||
x = np.array([(obj, 1.), (obj, 2.)],
|
||||
dtype=[('A', object), ('B', float)])
|
||||
y = np.array([10, 20], dtype=int)
|
||||
test = append_fields(x, 'C', data=y, usemask=False)
|
||||
control = np.array([(obj, 1.0, 10), (obj, 2.0, 20)],
|
||||
dtype=[('A', object), ('B', float), ('C', int)])
|
||||
assert_equal(test, control)
|
||||
@@ -0,0 +1,254 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import (
|
||||
assert_, assert_equal, assert_array_equal, assert_array_almost_equal,
|
||||
assert_raises, _assert_valid_refcount,
|
||||
)
|
||||
from numpy.compat import unicode
|
||||
|
||||
|
||||
class TestRegression(object):
|
||||
def test_poly1d(self):
|
||||
# Ticket #28
|
||||
assert_equal(np.poly1d([1]) - np.poly1d([1, 0]),
|
||||
np.poly1d([-1, 1]))
|
||||
|
||||
def test_cov_parameters(self):
|
||||
# Ticket #91
|
||||
x = np.random.random((3, 3))
|
||||
y = x.copy()
|
||||
np.cov(x, rowvar=1)
|
||||
np.cov(y, rowvar=0)
|
||||
assert_array_equal(x, y)
|
||||
|
||||
def test_mem_digitize(self):
|
||||
# Ticket #95
|
||||
for i in range(100):
|
||||
np.digitize([1, 2, 3, 4], [1, 3])
|
||||
np.digitize([0, 1, 2, 3, 4], [1, 3])
|
||||
|
||||
def test_unique_zero_sized(self):
|
||||
# Ticket #205
|
||||
assert_array_equal([], np.unique(np.array([])))
|
||||
|
||||
def test_mem_vectorise(self):
|
||||
# Ticket #325
|
||||
vt = np.vectorize(lambda *args: args)
|
||||
vt(np.zeros((1, 2, 1)), np.zeros((2, 1, 1)), np.zeros((1, 1, 2)))
|
||||
vt(np.zeros((1, 2, 1)), np.zeros((2, 1, 1)), np.zeros((1,
|
||||
1, 2)), np.zeros((2, 2)))
|
||||
|
||||
def test_mgrid_single_element(self):
|
||||
# Ticket #339
|
||||
assert_array_equal(np.mgrid[0:0:1j], [0])
|
||||
assert_array_equal(np.mgrid[0:0], [])
|
||||
|
||||
def test_refcount_vectorize(self):
|
||||
# Ticket #378
|
||||
def p(x, y):
|
||||
return 123
|
||||
v = np.vectorize(p)
|
||||
_assert_valid_refcount(v)
|
||||
|
||||
def test_poly1d_nan_roots(self):
|
||||
# Ticket #396
|
||||
p = np.poly1d([np.nan, np.nan, 1], r=0)
|
||||
assert_raises(np.linalg.LinAlgError, getattr, p, "r")
|
||||
|
||||
def test_mem_polymul(self):
|
||||
# Ticket #448
|
||||
np.polymul([], [1.])
|
||||
|
||||
def test_mem_string_concat(self):
|
||||
# Ticket #469
|
||||
x = np.array([])
|
||||
np.append(x, 'asdasd\tasdasd')
|
||||
|
||||
def test_poly_div(self):
|
||||
# Ticket #553
|
||||
u = np.poly1d([1, 2, 3])
|
||||
v = np.poly1d([1, 2, 3, 4, 5])
|
||||
q, r = np.polydiv(u, v)
|
||||
assert_equal(q*v + r, u)
|
||||
|
||||
def test_poly_eq(self):
|
||||
# Ticket #554
|
||||
x = np.poly1d([1, 2, 3])
|
||||
y = np.poly1d([3, 4])
|
||||
assert_(x != y)
|
||||
assert_(x == x)
|
||||
|
||||
def test_polyfit_build(self):
|
||||
# Ticket #628
|
||||
ref = [-1.06123820e-06, 5.70886914e-04, -1.13822012e-01,
|
||||
9.95368241e+00, -3.14526520e+02]
|
||||
x = [90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103,
|
||||
104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
|
||||
116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 129,
|
||||
130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
|
||||
146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157,
|
||||
158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
|
||||
170, 171, 172, 173, 174, 175, 176]
|
||||
y = [9.0, 3.0, 7.0, 4.0, 4.0, 8.0, 6.0, 11.0, 9.0, 8.0, 11.0, 5.0,
|
||||
6.0, 5.0, 9.0, 8.0, 6.0, 10.0, 6.0, 10.0, 7.0, 6.0, 6.0, 6.0,
|
||||
13.0, 4.0, 9.0, 11.0, 4.0, 5.0, 8.0, 5.0, 7.0, 7.0, 6.0, 12.0,
|
||||
7.0, 7.0, 9.0, 4.0, 12.0, 6.0, 6.0, 4.0, 3.0, 9.0, 8.0, 8.0,
|
||||
6.0, 7.0, 9.0, 10.0, 6.0, 8.0, 4.0, 7.0, 7.0, 10.0, 8.0, 8.0,
|
||||
6.0, 3.0, 8.0, 4.0, 5.0, 7.0, 8.0, 6.0, 6.0, 4.0, 12.0, 9.0,
|
||||
8.0, 8.0, 8.0, 6.0, 7.0, 4.0, 4.0, 5.0, 7.0]
|
||||
tested = np.polyfit(x, y, 4)
|
||||
assert_array_almost_equal(ref, tested)
|
||||
|
||||
def test_polydiv_type(self):
|
||||
# Make polydiv work for complex types
|
||||
msg = "Wrong type, should be complex"
|
||||
x = np.ones(3, dtype=complex)
|
||||
q, r = np.polydiv(x, x)
|
||||
assert_(q.dtype == complex, msg)
|
||||
msg = "Wrong type, should be float"
|
||||
x = np.ones(3, dtype=int)
|
||||
q, r = np.polydiv(x, x)
|
||||
assert_(q.dtype == float, msg)
|
||||
|
||||
def test_histogramdd_too_many_bins(self):
|
||||
# Ticket 928.
|
||||
assert_raises(ValueError, np.histogramdd, np.ones((1, 10)), bins=2**10)
|
||||
|
||||
def test_polyint_type(self):
|
||||
# Ticket #944
|
||||
msg = "Wrong type, should be complex"
|
||||
x = np.ones(3, dtype=complex)
|
||||
assert_(np.polyint(x).dtype == complex, msg)
|
||||
msg = "Wrong type, should be float"
|
||||
x = np.ones(3, dtype=int)
|
||||
assert_(np.polyint(x).dtype == float, msg)
|
||||
|
||||
def test_ndenumerate_crash(self):
|
||||
# Ticket 1140
|
||||
# Shouldn't crash:
|
||||
list(np.ndenumerate(np.array([[]])))
|
||||
|
||||
def test_asfarray_none(self):
|
||||
# Test for changeset r5065
|
||||
assert_array_equal(np.array([np.nan]), np.asfarray([None]))
|
||||
|
||||
def test_large_fancy_indexing(self):
|
||||
# Large enough to fail on 64-bit.
|
||||
nbits = np.dtype(np.intp).itemsize * 8
|
||||
thesize = int((2**nbits)**(1.0/5.0)+1)
|
||||
|
||||
def dp():
|
||||
n = 3
|
||||
a = np.ones((n,)*5)
|
||||
i = np.random.randint(0, n, size=thesize)
|
||||
a[np.ix_(i, i, i, i, i)] = 0
|
||||
|
||||
def dp2():
|
||||
n = 3
|
||||
a = np.ones((n,)*5)
|
||||
i = np.random.randint(0, n, size=thesize)
|
||||
a[np.ix_(i, i, i, i, i)]
|
||||
|
||||
assert_raises(ValueError, dp)
|
||||
assert_raises(ValueError, dp2)
|
||||
|
||||
def test_void_coercion(self):
|
||||
dt = np.dtype([('a', 'f4'), ('b', 'i4')])
|
||||
x = np.zeros((1,), dt)
|
||||
assert_(np.r_[x, x].dtype == dt)
|
||||
|
||||
def test_who_with_0dim_array(self):
|
||||
# ticket #1243
|
||||
import os
|
||||
import sys
|
||||
|
||||
oldstdout = sys.stdout
|
||||
sys.stdout = open(os.devnull, 'w')
|
||||
try:
|
||||
try:
|
||||
np.who({'foo': np.array(1)})
|
||||
except Exception:
|
||||
raise AssertionError("ticket #1243")
|
||||
finally:
|
||||
sys.stdout.close()
|
||||
sys.stdout = oldstdout
|
||||
|
||||
def test_include_dirs(self):
|
||||
# As a sanity check, just test that get_include
|
||||
# includes something reasonable. Somewhat
|
||||
# related to ticket #1405.
|
||||
include_dirs = [np.get_include()]
|
||||
for path in include_dirs:
|
||||
assert_(isinstance(path, (str, unicode)))
|
||||
assert_(path != '')
|
||||
|
||||
def test_polyder_return_type(self):
|
||||
# Ticket #1249
|
||||
assert_(isinstance(np.polyder(np.poly1d([1]), 0), np.poly1d))
|
||||
assert_(isinstance(np.polyder([1], 0), np.ndarray))
|
||||
assert_(isinstance(np.polyder(np.poly1d([1]), 1), np.poly1d))
|
||||
assert_(isinstance(np.polyder([1], 1), np.ndarray))
|
||||
|
||||
def test_append_fields_dtype_list(self):
|
||||
# Ticket #1676
|
||||
from numpy.lib.recfunctions import append_fields
|
||||
|
||||
base = np.array([1, 2, 3], dtype=np.int32)
|
||||
names = ['a', 'b', 'c']
|
||||
data = np.eye(3).astype(np.int32)
|
||||
dlist = [np.float64, np.int32, np.int32]
|
||||
try:
|
||||
append_fields(base, names, data, dlist)
|
||||
except Exception:
|
||||
raise AssertionError()
|
||||
|
||||
def test_loadtxt_fields_subarrays(self):
|
||||
# For ticket #1936
|
||||
if sys.version_info[0] >= 3:
|
||||
from io import StringIO
|
||||
else:
|
||||
from StringIO import StringIO
|
||||
|
||||
dt = [("a", 'u1', 2), ("b", 'u1', 2)]
|
||||
x = np.loadtxt(StringIO("0 1 2 3"), dtype=dt)
|
||||
assert_equal(x, np.array([((0, 1), (2, 3))], dtype=dt))
|
||||
|
||||
dt = [("a", [("a", 'u1', (1, 3)), ("b", 'u1')])]
|
||||
x = np.loadtxt(StringIO("0 1 2 3"), dtype=dt)
|
||||
assert_equal(x, np.array([(((0, 1, 2), 3),)], dtype=dt))
|
||||
|
||||
dt = [("a", 'u1', (2, 2))]
|
||||
x = np.loadtxt(StringIO("0 1 2 3"), dtype=dt)
|
||||
assert_equal(x, np.array([(((0, 1), (2, 3)),)], dtype=dt))
|
||||
|
||||
dt = [("a", 'u1', (2, 3, 2))]
|
||||
x = np.loadtxt(StringIO("0 1 2 3 4 5 6 7 8 9 10 11"), dtype=dt)
|
||||
data = [((((0, 1), (2, 3), (4, 5)), ((6, 7), (8, 9), (10, 11))),)]
|
||||
assert_equal(x, np.array(data, dtype=dt))
|
||||
|
||||
def test_nansum_with_boolean(self):
|
||||
# gh-2978
|
||||
a = np.zeros(2, dtype=bool)
|
||||
try:
|
||||
np.nansum(a)
|
||||
except Exception:
|
||||
raise AssertionError()
|
||||
|
||||
def test_py3_compat(self):
|
||||
# gh-2561
|
||||
# Test if the oldstyle class test is bypassed in python3
|
||||
class C():
|
||||
"""Old-style class in python2, normal class in python3"""
|
||||
pass
|
||||
|
||||
out = open(os.devnull, 'w')
|
||||
try:
|
||||
np.info(C(), output=out)
|
||||
except AttributeError:
|
||||
raise AssertionError()
|
||||
finally:
|
||||
out.close()
|
||||
@@ -0,0 +1,708 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import numpy as np
|
||||
import warnings
|
||||
import functools
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
from numpy.lib.shape_base import (
|
||||
apply_along_axis, apply_over_axes, array_split, split, hsplit, dsplit,
|
||||
vsplit, dstack, column_stack, kron, tile, expand_dims, take_along_axis,
|
||||
put_along_axis
|
||||
)
|
||||
from numpy.testing import (
|
||||
assert_, assert_equal, assert_array_equal, assert_raises, assert_warns
|
||||
)
|
||||
|
||||
|
||||
IS_64BIT = sys.maxsize > 2**32
|
||||
|
||||
|
||||
def _add_keepdims(func):
|
||||
""" hack in keepdims behavior into a function taking an axis """
|
||||
@functools.wraps(func)
|
||||
def wrapped(a, axis, **kwargs):
|
||||
res = func(a, axis=axis, **kwargs)
|
||||
if axis is None:
|
||||
axis = 0 # res is now a scalar, so we can insert this anywhere
|
||||
return np.expand_dims(res, axis=axis)
|
||||
return wrapped
|
||||
|
||||
|
||||
class TestTakeAlongAxis(object):
|
||||
def test_argequivalent(self):
|
||||
""" Test it translates from arg<func> to <func> """
|
||||
from numpy.random import rand
|
||||
a = rand(3, 4, 5)
|
||||
|
||||
funcs = [
|
||||
(np.sort, np.argsort, dict()),
|
||||
(_add_keepdims(np.min), _add_keepdims(np.argmin), dict()),
|
||||
(_add_keepdims(np.max), _add_keepdims(np.argmax), dict()),
|
||||
(np.partition, np.argpartition, dict(kth=2)),
|
||||
]
|
||||
|
||||
for func, argfunc, kwargs in funcs:
|
||||
for axis in list(range(a.ndim)) + [None]:
|
||||
a_func = func(a, axis=axis, **kwargs)
|
||||
ai_func = argfunc(a, axis=axis, **kwargs)
|
||||
assert_equal(a_func, take_along_axis(a, ai_func, axis=axis))
|
||||
|
||||
def test_invalid(self):
|
||||
""" Test it errors when indices has too few dimensions """
|
||||
a = np.ones((10, 10))
|
||||
ai = np.ones((10, 2), dtype=np.intp)
|
||||
|
||||
# sanity check
|
||||
take_along_axis(a, ai, axis=1)
|
||||
|
||||
# not enough indices
|
||||
assert_raises(ValueError, take_along_axis, a, np.array(1), axis=1)
|
||||
# bool arrays not allowed
|
||||
assert_raises(IndexError, take_along_axis, a, ai.astype(bool), axis=1)
|
||||
# float arrays not allowed
|
||||
assert_raises(IndexError, take_along_axis, a, ai.astype(float), axis=1)
|
||||
# invalid axis
|
||||
assert_raises(np.AxisError, take_along_axis, a, ai, axis=10)
|
||||
|
||||
def test_empty(self):
|
||||
""" Test everything is ok with empty results, even with inserted dims """
|
||||
a = np.ones((3, 4, 5))
|
||||
ai = np.ones((3, 0, 5), dtype=np.intp)
|
||||
|
||||
actual = take_along_axis(a, ai, axis=1)
|
||||
assert_equal(actual.shape, ai.shape)
|
||||
|
||||
def test_broadcast(self):
|
||||
""" Test that non-indexing dimensions are broadcast in both directions """
|
||||
a = np.ones((3, 4, 1))
|
||||
ai = np.ones((1, 2, 5), dtype=np.intp)
|
||||
actual = take_along_axis(a, ai, axis=1)
|
||||
assert_equal(actual.shape, (3, 2, 5))
|
||||
|
||||
|
||||
class TestPutAlongAxis(object):
|
||||
def test_replace_max(self):
|
||||
a_base = np.array([[10, 30, 20], [60, 40, 50]])
|
||||
|
||||
for axis in list(range(a_base.ndim)) + [None]:
|
||||
# we mutate this in the loop
|
||||
a = a_base.copy()
|
||||
|
||||
# replace the max with a small value
|
||||
i_max = _add_keepdims(np.argmax)(a, axis=axis)
|
||||
put_along_axis(a, i_max, -99, axis=axis)
|
||||
|
||||
# find the new minimum, which should max
|
||||
i_min = _add_keepdims(np.argmin)(a, axis=axis)
|
||||
|
||||
assert_equal(i_min, i_max)
|
||||
|
||||
def test_broadcast(self):
|
||||
""" Test that non-indexing dimensions are broadcast in both directions """
|
||||
a = np.ones((3, 4, 1))
|
||||
ai = np.arange(10, dtype=np.intp).reshape((1, 2, 5)) % 4
|
||||
put_along_axis(a, ai, 20, axis=1)
|
||||
assert_equal(take_along_axis(a, ai, axis=1), 20)
|
||||
|
||||
|
||||
class TestApplyAlongAxis(object):
|
||||
def test_simple(self):
|
||||
a = np.ones((20, 10), 'd')
|
||||
assert_array_equal(
|
||||
apply_along_axis(len, 0, a), len(a)*np.ones(a.shape[1]))
|
||||
|
||||
def test_simple101(self):
|
||||
a = np.ones((10, 101), 'd')
|
||||
assert_array_equal(
|
||||
apply_along_axis(len, 0, a), len(a)*np.ones(a.shape[1]))
|
||||
|
||||
def test_3d(self):
|
||||
a = np.arange(27).reshape((3, 3, 3))
|
||||
assert_array_equal(apply_along_axis(np.sum, 0, a),
|
||||
[[27, 30, 33], [36, 39, 42], [45, 48, 51]])
|
||||
|
||||
def test_preserve_subclass(self):
|
||||
def double(row):
|
||||
return row * 2
|
||||
|
||||
class MyNDArray(np.ndarray):
|
||||
pass
|
||||
|
||||
m = np.array([[0, 1], [2, 3]]).view(MyNDArray)
|
||||
expected = np.array([[0, 2], [4, 6]]).view(MyNDArray)
|
||||
|
||||
result = apply_along_axis(double, 0, m)
|
||||
assert_(isinstance(result, MyNDArray))
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
result = apply_along_axis(double, 1, m)
|
||||
assert_(isinstance(result, MyNDArray))
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
def test_subclass(self):
|
||||
class MinimalSubclass(np.ndarray):
|
||||
data = 1
|
||||
|
||||
def minimal_function(array):
|
||||
return array.data
|
||||
|
||||
a = np.zeros((6, 3)).view(MinimalSubclass)
|
||||
|
||||
assert_array_equal(
|
||||
apply_along_axis(minimal_function, 0, a), np.array([1, 1, 1])
|
||||
)
|
||||
|
||||
def test_scalar_array(self, cls=np.ndarray):
|
||||
a = np.ones((6, 3)).view(cls)
|
||||
res = apply_along_axis(np.sum, 0, a)
|
||||
assert_(isinstance(res, cls))
|
||||
assert_array_equal(res, np.array([6, 6, 6]).view(cls))
|
||||
|
||||
def test_0d_array(self, cls=np.ndarray):
|
||||
def sum_to_0d(x):
|
||||
""" Sum x, returning a 0d array of the same class """
|
||||
assert_equal(x.ndim, 1)
|
||||
return np.squeeze(np.sum(x, keepdims=True))
|
||||
a = np.ones((6, 3)).view(cls)
|
||||
res = apply_along_axis(sum_to_0d, 0, a)
|
||||
assert_(isinstance(res, cls))
|
||||
assert_array_equal(res, np.array([6, 6, 6]).view(cls))
|
||||
|
||||
res = apply_along_axis(sum_to_0d, 1, a)
|
||||
assert_(isinstance(res, cls))
|
||||
assert_array_equal(res, np.array([3, 3, 3, 3, 3, 3]).view(cls))
|
||||
|
||||
def test_axis_insertion(self, cls=np.ndarray):
|
||||
def f1to2(x):
|
||||
"""produces an asymmetric non-square matrix from x"""
|
||||
assert_equal(x.ndim, 1)
|
||||
return (x[::-1] * x[1:,None]).view(cls)
|
||||
|
||||
a2d = np.arange(6*3).reshape((6, 3))
|
||||
|
||||
# 2d insertion along first axis
|
||||
actual = apply_along_axis(f1to2, 0, a2d)
|
||||
expected = np.stack([
|
||||
f1to2(a2d[:,i]) for i in range(a2d.shape[1])
|
||||
], axis=-1).view(cls)
|
||||
assert_equal(type(actual), type(expected))
|
||||
assert_equal(actual, expected)
|
||||
|
||||
# 2d insertion along last axis
|
||||
actual = apply_along_axis(f1to2, 1, a2d)
|
||||
expected = np.stack([
|
||||
f1to2(a2d[i,:]) for i in range(a2d.shape[0])
|
||||
], axis=0).view(cls)
|
||||
assert_equal(type(actual), type(expected))
|
||||
assert_equal(actual, expected)
|
||||
|
||||
# 3d insertion along middle axis
|
||||
a3d = np.arange(6*5*3).reshape((6, 5, 3))
|
||||
|
||||
actual = apply_along_axis(f1to2, 1, a3d)
|
||||
expected = np.stack([
|
||||
np.stack([
|
||||
f1to2(a3d[i,:,j]) for i in range(a3d.shape[0])
|
||||
], axis=0)
|
||||
for j in range(a3d.shape[2])
|
||||
], axis=-1).view(cls)
|
||||
assert_equal(type(actual), type(expected))
|
||||
assert_equal(actual, expected)
|
||||
|
||||
def test_subclass_preservation(self):
|
||||
class MinimalSubclass(np.ndarray):
|
||||
pass
|
||||
self.test_scalar_array(MinimalSubclass)
|
||||
self.test_0d_array(MinimalSubclass)
|
||||
self.test_axis_insertion(MinimalSubclass)
|
||||
|
||||
def test_axis_insertion_ma(self):
|
||||
def f1to2(x):
|
||||
"""produces an asymmetric non-square matrix from x"""
|
||||
assert_equal(x.ndim, 1)
|
||||
res = x[::-1] * x[1:,None]
|
||||
return np.ma.masked_where(res%5==0, res)
|
||||
a = np.arange(6*3).reshape((6, 3))
|
||||
res = apply_along_axis(f1to2, 0, a)
|
||||
assert_(isinstance(res, np.ma.masked_array))
|
||||
assert_equal(res.ndim, 3)
|
||||
assert_array_equal(res[:,:,0].mask, f1to2(a[:,0]).mask)
|
||||
assert_array_equal(res[:,:,1].mask, f1to2(a[:,1]).mask)
|
||||
assert_array_equal(res[:,:,2].mask, f1to2(a[:,2]).mask)
|
||||
|
||||
def test_tuple_func1d(self):
|
||||
def sample_1d(x):
|
||||
return x[1], x[0]
|
||||
res = np.apply_along_axis(sample_1d, 1, np.array([[1, 2], [3, 4]]))
|
||||
assert_array_equal(res, np.array([[2, 1], [4, 3]]))
|
||||
|
||||
def test_empty(self):
|
||||
# can't apply_along_axis when there's no chance to call the function
|
||||
def never_call(x):
|
||||
assert_(False) # should never be reached
|
||||
|
||||
a = np.empty((0, 0))
|
||||
assert_raises(ValueError, np.apply_along_axis, never_call, 0, a)
|
||||
assert_raises(ValueError, np.apply_along_axis, never_call, 1, a)
|
||||
|
||||
# but it's sometimes ok with some non-zero dimensions
|
||||
def empty_to_1(x):
|
||||
assert_(len(x) == 0)
|
||||
return 1
|
||||
|
||||
a = np.empty((10, 0))
|
||||
actual = np.apply_along_axis(empty_to_1, 1, a)
|
||||
assert_equal(actual, np.ones(10))
|
||||
assert_raises(ValueError, np.apply_along_axis, empty_to_1, 0, a)
|
||||
|
||||
def test_with_iterable_object(self):
|
||||
# from issue 5248
|
||||
d = np.array([
|
||||
[{1, 11}, {2, 22}, {3, 33}],
|
||||
[{4, 44}, {5, 55}, {6, 66}]
|
||||
])
|
||||
actual = np.apply_along_axis(lambda a: set.union(*a), 0, d)
|
||||
expected = np.array([{1, 11, 4, 44}, {2, 22, 5, 55}, {3, 33, 6, 66}])
|
||||
|
||||
assert_equal(actual, expected)
|
||||
|
||||
# issue 8642 - assert_equal doesn't detect this!
|
||||
for i in np.ndindex(actual.shape):
|
||||
assert_equal(type(actual[i]), type(expected[i]))
|
||||
|
||||
|
||||
class TestApplyOverAxes(object):
|
||||
def test_simple(self):
|
||||
a = np.arange(24).reshape(2, 3, 4)
|
||||
aoa_a = apply_over_axes(np.sum, a, [0, 2])
|
||||
assert_array_equal(aoa_a, np.array([[[60], [92], [124]]]))
|
||||
|
||||
|
||||
class TestExpandDims(object):
|
||||
def test_functionality(self):
|
||||
s = (2, 3, 4, 5)
|
||||
a = np.empty(s)
|
||||
for axis in range(-5, 4):
|
||||
b = expand_dims(a, axis)
|
||||
assert_(b.shape[axis] == 1)
|
||||
assert_(np.squeeze(b).shape == s)
|
||||
|
||||
def test_deprecations(self):
|
||||
# 2017-05-17, 1.13.0
|
||||
s = (2, 3, 4, 5)
|
||||
a = np.empty(s)
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("always")
|
||||
assert_warns(DeprecationWarning, expand_dims, a, -6)
|
||||
assert_warns(DeprecationWarning, expand_dims, a, 5)
|
||||
|
||||
def test_subclasses(self):
|
||||
a = np.arange(10).reshape((2, 5))
|
||||
a = np.ma.array(a, mask=a%3 == 0)
|
||||
|
||||
expanded = np.expand_dims(a, axis=1)
|
||||
assert_(isinstance(expanded, np.ma.MaskedArray))
|
||||
assert_equal(expanded.shape, (2, 1, 5))
|
||||
assert_equal(expanded.mask.shape, (2, 1, 5))
|
||||
|
||||
|
||||
class TestArraySplit(object):
|
||||
def test_integer_0_split(self):
|
||||
a = np.arange(10)
|
||||
assert_raises(ValueError, array_split, a, 0)
|
||||
|
||||
def test_integer_split(self):
|
||||
a = np.arange(10)
|
||||
res = array_split(a, 1)
|
||||
desired = [np.arange(10)]
|
||||
compare_results(res, desired)
|
||||
|
||||
res = array_split(a, 2)
|
||||
desired = [np.arange(5), np.arange(5, 10)]
|
||||
compare_results(res, desired)
|
||||
|
||||
res = array_split(a, 3)
|
||||
desired = [np.arange(4), np.arange(4, 7), np.arange(7, 10)]
|
||||
compare_results(res, desired)
|
||||
|
||||
res = array_split(a, 4)
|
||||
desired = [np.arange(3), np.arange(3, 6), np.arange(6, 8),
|
||||
np.arange(8, 10)]
|
||||
compare_results(res, desired)
|
||||
|
||||
res = array_split(a, 5)
|
||||
desired = [np.arange(2), np.arange(2, 4), np.arange(4, 6),
|
||||
np.arange(6, 8), np.arange(8, 10)]
|
||||
compare_results(res, desired)
|
||||
|
||||
res = array_split(a, 6)
|
||||
desired = [np.arange(2), np.arange(2, 4), np.arange(4, 6),
|
||||
np.arange(6, 8), np.arange(8, 9), np.arange(9, 10)]
|
||||
compare_results(res, desired)
|
||||
|
||||
res = array_split(a, 7)
|
||||
desired = [np.arange(2), np.arange(2, 4), np.arange(4, 6),
|
||||
np.arange(6, 7), np.arange(7, 8), np.arange(8, 9),
|
||||
np.arange(9, 10)]
|
||||
compare_results(res, desired)
|
||||
|
||||
res = array_split(a, 8)
|
||||
desired = [np.arange(2), np.arange(2, 4), np.arange(4, 5),
|
||||
np.arange(5, 6), np.arange(6, 7), np.arange(7, 8),
|
||||
np.arange(8, 9), np.arange(9, 10)]
|
||||
compare_results(res, desired)
|
||||
|
||||
res = array_split(a, 9)
|
||||
desired = [np.arange(2), np.arange(2, 3), np.arange(3, 4),
|
||||
np.arange(4, 5), np.arange(5, 6), np.arange(6, 7),
|
||||
np.arange(7, 8), np.arange(8, 9), np.arange(9, 10)]
|
||||
compare_results(res, desired)
|
||||
|
||||
res = array_split(a, 10)
|
||||
desired = [np.arange(1), np.arange(1, 2), np.arange(2, 3),
|
||||
np.arange(3, 4), np.arange(4, 5), np.arange(5, 6),
|
||||
np.arange(6, 7), np.arange(7, 8), np.arange(8, 9),
|
||||
np.arange(9, 10)]
|
||||
compare_results(res, desired)
|
||||
|
||||
res = array_split(a, 11)
|
||||
desired = [np.arange(1), np.arange(1, 2), np.arange(2, 3),
|
||||
np.arange(3, 4), np.arange(4, 5), np.arange(5, 6),
|
||||
np.arange(6, 7), np.arange(7, 8), np.arange(8, 9),
|
||||
np.arange(9, 10), np.array([])]
|
||||
compare_results(res, desired)
|
||||
|
||||
def test_integer_split_2D_rows(self):
|
||||
a = np.array([np.arange(10), np.arange(10)])
|
||||
res = array_split(a, 3, axis=0)
|
||||
tgt = [np.array([np.arange(10)]), np.array([np.arange(10)]),
|
||||
np.zeros((0, 10))]
|
||||
compare_results(res, tgt)
|
||||
assert_(a.dtype.type is res[-1].dtype.type)
|
||||
|
||||
# Same thing for manual splits:
|
||||
res = array_split(a, [0, 1, 2], axis=0)
|
||||
tgt = [np.zeros((0, 10)), np.array([np.arange(10)]),
|
||||
np.array([np.arange(10)])]
|
||||
compare_results(res, tgt)
|
||||
assert_(a.dtype.type is res[-1].dtype.type)
|
||||
|
||||
def test_integer_split_2D_cols(self):
|
||||
a = np.array([np.arange(10), np.arange(10)])
|
||||
res = array_split(a, 3, axis=-1)
|
||||
desired = [np.array([np.arange(4), np.arange(4)]),
|
||||
np.array([np.arange(4, 7), np.arange(4, 7)]),
|
||||
np.array([np.arange(7, 10), np.arange(7, 10)])]
|
||||
compare_results(res, desired)
|
||||
|
||||
def test_integer_split_2D_default(self):
|
||||
""" This will fail if we change default axis
|
||||
"""
|
||||
a = np.array([np.arange(10), np.arange(10)])
|
||||
res = array_split(a, 3)
|
||||
tgt = [np.array([np.arange(10)]), np.array([np.arange(10)]),
|
||||
np.zeros((0, 10))]
|
||||
compare_results(res, tgt)
|
||||
assert_(a.dtype.type is res[-1].dtype.type)
|
||||
# perhaps should check higher dimensions
|
||||
|
||||
@pytest.mark.skipif(not IS_64BIT, reason="Needs 64bit platform")
|
||||
def test_integer_split_2D_rows_greater_max_int32(self):
|
||||
a = np.broadcast_to([0], (1 << 32, 2))
|
||||
res = array_split(a, 4)
|
||||
chunk = np.broadcast_to([0], (1 << 30, 2))
|
||||
tgt = [chunk] * 4
|
||||
for i in range(len(tgt)):
|
||||
assert_equal(res[i].shape, tgt[i].shape)
|
||||
|
||||
def test_index_split_simple(self):
|
||||
a = np.arange(10)
|
||||
indices = [1, 5, 7]
|
||||
res = array_split(a, indices, axis=-1)
|
||||
desired = [np.arange(0, 1), np.arange(1, 5), np.arange(5, 7),
|
||||
np.arange(7, 10)]
|
||||
compare_results(res, desired)
|
||||
|
||||
def test_index_split_low_bound(self):
|
||||
a = np.arange(10)
|
||||
indices = [0, 5, 7]
|
||||
res = array_split(a, indices, axis=-1)
|
||||
desired = [np.array([]), np.arange(0, 5), np.arange(5, 7),
|
||||
np.arange(7, 10)]
|
||||
compare_results(res, desired)
|
||||
|
||||
def test_index_split_high_bound(self):
|
||||
a = np.arange(10)
|
||||
indices = [0, 5, 7, 10, 12]
|
||||
res = array_split(a, indices, axis=-1)
|
||||
desired = [np.array([]), np.arange(0, 5), np.arange(5, 7),
|
||||
np.arange(7, 10), np.array([]), np.array([])]
|
||||
compare_results(res, desired)
|
||||
|
||||
|
||||
class TestSplit(object):
|
||||
# The split function is essentially the same as array_split,
|
||||
# except that it test if splitting will result in an
|
||||
# equal split. Only test for this case.
|
||||
|
||||
def test_equal_split(self):
|
||||
a = np.arange(10)
|
||||
res = split(a, 2)
|
||||
desired = [np.arange(5), np.arange(5, 10)]
|
||||
compare_results(res, desired)
|
||||
|
||||
def test_unequal_split(self):
|
||||
a = np.arange(10)
|
||||
assert_raises(ValueError, split, a, 3)
|
||||
|
||||
|
||||
class TestColumnStack(object):
|
||||
def test_non_iterable(self):
|
||||
assert_raises(TypeError, column_stack, 1)
|
||||
|
||||
def test_1D_arrays(self):
|
||||
# example from docstring
|
||||
a = np.array((1, 2, 3))
|
||||
b = np.array((2, 3, 4))
|
||||
expected = np.array([[1, 2],
|
||||
[2, 3],
|
||||
[3, 4]])
|
||||
actual = np.column_stack((a, b))
|
||||
assert_equal(actual, expected)
|
||||
|
||||
def test_2D_arrays(self):
|
||||
# same as hstack 2D docstring example
|
||||
a = np.array([[1], [2], [3]])
|
||||
b = np.array([[2], [3], [4]])
|
||||
expected = np.array([[1, 2],
|
||||
[2, 3],
|
||||
[3, 4]])
|
||||
actual = np.column_stack((a, b))
|
||||
assert_equal(actual, expected)
|
||||
|
||||
def test_generator(self):
|
||||
with assert_warns(FutureWarning):
|
||||
column_stack((np.arange(3) for _ in range(2)))
|
||||
|
||||
|
||||
class TestDstack(object):
|
||||
def test_non_iterable(self):
|
||||
assert_raises(TypeError, dstack, 1)
|
||||
|
||||
def test_0D_array(self):
|
||||
a = np.array(1)
|
||||
b = np.array(2)
|
||||
res = dstack([a, b])
|
||||
desired = np.array([[[1, 2]]])
|
||||
assert_array_equal(res, desired)
|
||||
|
||||
def test_1D_array(self):
|
||||
a = np.array([1])
|
||||
b = np.array([2])
|
||||
res = dstack([a, b])
|
||||
desired = np.array([[[1, 2]]])
|
||||
assert_array_equal(res, desired)
|
||||
|
||||
def test_2D_array(self):
|
||||
a = np.array([[1], [2]])
|
||||
b = np.array([[1], [2]])
|
||||
res = dstack([a, b])
|
||||
desired = np.array([[[1, 1]], [[2, 2, ]]])
|
||||
assert_array_equal(res, desired)
|
||||
|
||||
def test_2D_array2(self):
|
||||
a = np.array([1, 2])
|
||||
b = np.array([1, 2])
|
||||
res = dstack([a, b])
|
||||
desired = np.array([[[1, 1], [2, 2]]])
|
||||
assert_array_equal(res, desired)
|
||||
|
||||
def test_generator(self):
|
||||
with assert_warns(FutureWarning):
|
||||
dstack((np.arange(3) for _ in range(2)))
|
||||
|
||||
|
||||
# array_split has more comprehensive test of splitting.
|
||||
# only do simple test on hsplit, vsplit, and dsplit
|
||||
class TestHsplit(object):
|
||||
"""Only testing for integer splits.
|
||||
|
||||
"""
|
||||
def test_non_iterable(self):
|
||||
assert_raises(ValueError, hsplit, 1, 1)
|
||||
|
||||
def test_0D_array(self):
|
||||
a = np.array(1)
|
||||
try:
|
||||
hsplit(a, 2)
|
||||
assert_(0)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def test_1D_array(self):
|
||||
a = np.array([1, 2, 3, 4])
|
||||
res = hsplit(a, 2)
|
||||
desired = [np.array([1, 2]), np.array([3, 4])]
|
||||
compare_results(res, desired)
|
||||
|
||||
def test_2D_array(self):
|
||||
a = np.array([[1, 2, 3, 4],
|
||||
[1, 2, 3, 4]])
|
||||
res = hsplit(a, 2)
|
||||
desired = [np.array([[1, 2], [1, 2]]), np.array([[3, 4], [3, 4]])]
|
||||
compare_results(res, desired)
|
||||
|
||||
|
||||
class TestVsplit(object):
|
||||
"""Only testing for integer splits.
|
||||
|
||||
"""
|
||||
def test_non_iterable(self):
|
||||
assert_raises(ValueError, vsplit, 1, 1)
|
||||
|
||||
def test_0D_array(self):
|
||||
a = np.array(1)
|
||||
assert_raises(ValueError, vsplit, a, 2)
|
||||
|
||||
def test_1D_array(self):
|
||||
a = np.array([1, 2, 3, 4])
|
||||
try:
|
||||
vsplit(a, 2)
|
||||
assert_(0)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def test_2D_array(self):
|
||||
a = np.array([[1, 2, 3, 4],
|
||||
[1, 2, 3, 4]])
|
||||
res = vsplit(a, 2)
|
||||
desired = [np.array([[1, 2, 3, 4]]), np.array([[1, 2, 3, 4]])]
|
||||
compare_results(res, desired)
|
||||
|
||||
|
||||
class TestDsplit(object):
|
||||
# Only testing for integer splits.
|
||||
def test_non_iterable(self):
|
||||
assert_raises(ValueError, dsplit, 1, 1)
|
||||
|
||||
def test_0D_array(self):
|
||||
a = np.array(1)
|
||||
assert_raises(ValueError, dsplit, a, 2)
|
||||
|
||||
def test_1D_array(self):
|
||||
a = np.array([1, 2, 3, 4])
|
||||
assert_raises(ValueError, dsplit, a, 2)
|
||||
|
||||
def test_2D_array(self):
|
||||
a = np.array([[1, 2, 3, 4],
|
||||
[1, 2, 3, 4]])
|
||||
try:
|
||||
dsplit(a, 2)
|
||||
assert_(0)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def test_3D_array(self):
|
||||
a = np.array([[[1, 2, 3, 4],
|
||||
[1, 2, 3, 4]],
|
||||
[[1, 2, 3, 4],
|
||||
[1, 2, 3, 4]]])
|
||||
res = dsplit(a, 2)
|
||||
desired = [np.array([[[1, 2], [1, 2]], [[1, 2], [1, 2]]]),
|
||||
np.array([[[3, 4], [3, 4]], [[3, 4], [3, 4]]])]
|
||||
compare_results(res, desired)
|
||||
|
||||
|
||||
class TestSqueeze(object):
|
||||
def test_basic(self):
|
||||
from numpy.random import rand
|
||||
|
||||
a = rand(20, 10, 10, 1, 1)
|
||||
b = rand(20, 1, 10, 1, 20)
|
||||
c = rand(1, 1, 20, 10)
|
||||
assert_array_equal(np.squeeze(a), np.reshape(a, (20, 10, 10)))
|
||||
assert_array_equal(np.squeeze(b), np.reshape(b, (20, 10, 20)))
|
||||
assert_array_equal(np.squeeze(c), np.reshape(c, (20, 10)))
|
||||
|
||||
# Squeezing to 0-dim should still give an ndarray
|
||||
a = [[[1.5]]]
|
||||
res = np.squeeze(a)
|
||||
assert_equal(res, 1.5)
|
||||
assert_equal(res.ndim, 0)
|
||||
assert_equal(type(res), np.ndarray)
|
||||
|
||||
|
||||
class TestKron(object):
|
||||
def test_return_type(self):
|
||||
class myarray(np.ndarray):
|
||||
__array_priority__ = 0.0
|
||||
|
||||
a = np.ones([2, 2])
|
||||
ma = myarray(a.shape, a.dtype, a.data)
|
||||
assert_equal(type(kron(a, a)), np.ndarray)
|
||||
assert_equal(type(kron(ma, ma)), myarray)
|
||||
assert_equal(type(kron(a, ma)), np.ndarray)
|
||||
assert_equal(type(kron(ma, a)), myarray)
|
||||
|
||||
|
||||
class TestTile(object):
|
||||
def test_basic(self):
|
||||
a = np.array([0, 1, 2])
|
||||
b = [[1, 2], [3, 4]]
|
||||
assert_equal(tile(a, 2), [0, 1, 2, 0, 1, 2])
|
||||
assert_equal(tile(a, (2, 2)), [[0, 1, 2, 0, 1, 2], [0, 1, 2, 0, 1, 2]])
|
||||
assert_equal(tile(a, (1, 2)), [[0, 1, 2, 0, 1, 2]])
|
||||
assert_equal(tile(b, 2), [[1, 2, 1, 2], [3, 4, 3, 4]])
|
||||
assert_equal(tile(b, (2, 1)), [[1, 2], [3, 4], [1, 2], [3, 4]])
|
||||
assert_equal(tile(b, (2, 2)), [[1, 2, 1, 2], [3, 4, 3, 4],
|
||||
[1, 2, 1, 2], [3, 4, 3, 4]])
|
||||
|
||||
def test_tile_one_repetition_on_array_gh4679(self):
|
||||
a = np.arange(5)
|
||||
b = tile(a, 1)
|
||||
b += 2
|
||||
assert_equal(a, np.arange(5))
|
||||
|
||||
def test_empty(self):
|
||||
a = np.array([[[]]])
|
||||
b = np.array([[], []])
|
||||
c = tile(b, 2).shape
|
||||
d = tile(a, (3, 2, 5)).shape
|
||||
assert_equal(c, (2, 0))
|
||||
assert_equal(d, (3, 2, 0))
|
||||
|
||||
def test_kroncompare(self):
|
||||
from numpy.random import randint
|
||||
|
||||
reps = [(2,), (1, 2), (2, 1), (2, 2), (2, 3, 2), (3, 2)]
|
||||
shape = [(3,), (2, 3), (3, 4, 3), (3, 2, 3), (4, 3, 2, 4), (2, 2)]
|
||||
for s in shape:
|
||||
b = randint(0, 10, size=s)
|
||||
for r in reps:
|
||||
a = np.ones(r, b.dtype)
|
||||
large = tile(b, r)
|
||||
klarge = kron(a, b)
|
||||
assert_equal(large, klarge)
|
||||
|
||||
|
||||
class TestMayShareMemory(object):
|
||||
def test_basic(self):
|
||||
d = np.ones((50, 60))
|
||||
d2 = np.ones((30, 60, 6))
|
||||
assert_(np.may_share_memory(d, d))
|
||||
assert_(np.may_share_memory(d, d[::-1]))
|
||||
assert_(np.may_share_memory(d, d[::2]))
|
||||
assert_(np.may_share_memory(d, d[1:, ::-1]))
|
||||
|
||||
assert_(not np.may_share_memory(d[::-1], d2))
|
||||
assert_(not np.may_share_memory(d[::2], d2))
|
||||
assert_(not np.may_share_memory(d[1:, ::-1], d2))
|
||||
assert_(np.may_share_memory(d2[1:, ::-1], d2))
|
||||
|
||||
|
||||
# Utility
|
||||
def compare_results(res, desired):
|
||||
for i in range(len(desired)):
|
||||
assert_array_equal(res[i], desired[i])
|
||||
@@ -0,0 +1,445 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import numpy as np
|
||||
from numpy.core._rational_tests import rational
|
||||
from numpy.testing import (
|
||||
assert_equal, assert_array_equal, assert_raises, assert_,
|
||||
assert_raises_regex
|
||||
)
|
||||
from numpy.lib.stride_tricks import (
|
||||
as_strided, broadcast_arrays, _broadcast_shape, broadcast_to
|
||||
)
|
||||
|
||||
def assert_shapes_correct(input_shapes, expected_shape):
|
||||
# Broadcast a list of arrays with the given input shapes and check the
|
||||
# common output shape.
|
||||
|
||||
inarrays = [np.zeros(s) for s in input_shapes]
|
||||
outarrays = broadcast_arrays(*inarrays)
|
||||
outshapes = [a.shape for a in outarrays]
|
||||
expected = [expected_shape] * len(inarrays)
|
||||
assert_equal(outshapes, expected)
|
||||
|
||||
|
||||
def assert_incompatible_shapes_raise(input_shapes):
|
||||
# Broadcast a list of arrays with the given (incompatible) input shapes
|
||||
# and check that they raise a ValueError.
|
||||
|
||||
inarrays = [np.zeros(s) for s in input_shapes]
|
||||
assert_raises(ValueError, broadcast_arrays, *inarrays)
|
||||
|
||||
|
||||
def assert_same_as_ufunc(shape0, shape1, transposed=False, flipped=False):
|
||||
# Broadcast two shapes against each other and check that the data layout
|
||||
# is the same as if a ufunc did the broadcasting.
|
||||
|
||||
x0 = np.zeros(shape0, dtype=int)
|
||||
# Note that multiply.reduce's identity element is 1.0, so when shape1==(),
|
||||
# this gives the desired n==1.
|
||||
n = int(np.multiply.reduce(shape1))
|
||||
x1 = np.arange(n).reshape(shape1)
|
||||
if transposed:
|
||||
x0 = x0.T
|
||||
x1 = x1.T
|
||||
if flipped:
|
||||
x0 = x0[::-1]
|
||||
x1 = x1[::-1]
|
||||
# Use the add ufunc to do the broadcasting. Since we're adding 0s to x1, the
|
||||
# result should be exactly the same as the broadcasted view of x1.
|
||||
y = x0 + x1
|
||||
b0, b1 = broadcast_arrays(x0, x1)
|
||||
assert_array_equal(y, b1)
|
||||
|
||||
|
||||
def test_same():
|
||||
x = np.arange(10)
|
||||
y = np.arange(10)
|
||||
bx, by = broadcast_arrays(x, y)
|
||||
assert_array_equal(x, bx)
|
||||
assert_array_equal(y, by)
|
||||
|
||||
def test_broadcast_kwargs():
|
||||
# ensure that a TypeError is appropriately raised when
|
||||
# np.broadcast_arrays() is called with any keyword
|
||||
# argument other than 'subok'
|
||||
x = np.arange(10)
|
||||
y = np.arange(10)
|
||||
|
||||
with assert_raises_regex(TypeError,
|
||||
r'broadcast_arrays\(\) got an unexpected keyword*'):
|
||||
broadcast_arrays(x, y, dtype='float64')
|
||||
|
||||
|
||||
def test_one_off():
|
||||
x = np.array([[1, 2, 3]])
|
||||
y = np.array([[1], [2], [3]])
|
||||
bx, by = broadcast_arrays(x, y)
|
||||
bx0 = np.array([[1, 2, 3], [1, 2, 3], [1, 2, 3]])
|
||||
by0 = bx0.T
|
||||
assert_array_equal(bx0, bx)
|
||||
assert_array_equal(by0, by)
|
||||
|
||||
|
||||
def test_same_input_shapes():
|
||||
# Check that the final shape is just the input shape.
|
||||
|
||||
data = [
|
||||
(),
|
||||
(1,),
|
||||
(3,),
|
||||
(0, 1),
|
||||
(0, 3),
|
||||
(1, 0),
|
||||
(3, 0),
|
||||
(1, 3),
|
||||
(3, 1),
|
||||
(3, 3),
|
||||
]
|
||||
for shape in data:
|
||||
input_shapes = [shape]
|
||||
# Single input.
|
||||
assert_shapes_correct(input_shapes, shape)
|
||||
# Double input.
|
||||
input_shapes2 = [shape, shape]
|
||||
assert_shapes_correct(input_shapes2, shape)
|
||||
# Triple input.
|
||||
input_shapes3 = [shape, shape, shape]
|
||||
assert_shapes_correct(input_shapes3, shape)
|
||||
|
||||
|
||||
def test_two_compatible_by_ones_input_shapes():
|
||||
# Check that two different input shapes of the same length, but some have
|
||||
# ones, broadcast to the correct shape.
|
||||
|
||||
data = [
|
||||
[[(1,), (3,)], (3,)],
|
||||
[[(1, 3), (3, 3)], (3, 3)],
|
||||
[[(3, 1), (3, 3)], (3, 3)],
|
||||
[[(1, 3), (3, 1)], (3, 3)],
|
||||
[[(1, 1), (3, 3)], (3, 3)],
|
||||
[[(1, 1), (1, 3)], (1, 3)],
|
||||
[[(1, 1), (3, 1)], (3, 1)],
|
||||
[[(1, 0), (0, 0)], (0, 0)],
|
||||
[[(0, 1), (0, 0)], (0, 0)],
|
||||
[[(1, 0), (0, 1)], (0, 0)],
|
||||
[[(1, 1), (0, 0)], (0, 0)],
|
||||
[[(1, 1), (1, 0)], (1, 0)],
|
||||
[[(1, 1), (0, 1)], (0, 1)],
|
||||
]
|
||||
for input_shapes, expected_shape in data:
|
||||
assert_shapes_correct(input_shapes, expected_shape)
|
||||
# Reverse the input shapes since broadcasting should be symmetric.
|
||||
assert_shapes_correct(input_shapes[::-1], expected_shape)
|
||||
|
||||
|
||||
def test_two_compatible_by_prepending_ones_input_shapes():
|
||||
# Check that two different input shapes (of different lengths) broadcast
|
||||
# to the correct shape.
|
||||
|
||||
data = [
|
||||
[[(), (3,)], (3,)],
|
||||
[[(3,), (3, 3)], (3, 3)],
|
||||
[[(3,), (3, 1)], (3, 3)],
|
||||
[[(1,), (3, 3)], (3, 3)],
|
||||
[[(), (3, 3)], (3, 3)],
|
||||
[[(1, 1), (3,)], (1, 3)],
|
||||
[[(1,), (3, 1)], (3, 1)],
|
||||
[[(1,), (1, 3)], (1, 3)],
|
||||
[[(), (1, 3)], (1, 3)],
|
||||
[[(), (3, 1)], (3, 1)],
|
||||
[[(), (0,)], (0,)],
|
||||
[[(0,), (0, 0)], (0, 0)],
|
||||
[[(0,), (0, 1)], (0, 0)],
|
||||
[[(1,), (0, 0)], (0, 0)],
|
||||
[[(), (0, 0)], (0, 0)],
|
||||
[[(1, 1), (0,)], (1, 0)],
|
||||
[[(1,), (0, 1)], (0, 1)],
|
||||
[[(1,), (1, 0)], (1, 0)],
|
||||
[[(), (1, 0)], (1, 0)],
|
||||
[[(), (0, 1)], (0, 1)],
|
||||
]
|
||||
for input_shapes, expected_shape in data:
|
||||
assert_shapes_correct(input_shapes, expected_shape)
|
||||
# Reverse the input shapes since broadcasting should be symmetric.
|
||||
assert_shapes_correct(input_shapes[::-1], expected_shape)
|
||||
|
||||
|
||||
def test_incompatible_shapes_raise_valueerror():
|
||||
# Check that a ValueError is raised for incompatible shapes.
|
||||
|
||||
data = [
|
||||
[(3,), (4,)],
|
||||
[(2, 3), (2,)],
|
||||
[(3,), (3,), (4,)],
|
||||
[(1, 3, 4), (2, 3, 3)],
|
||||
]
|
||||
for input_shapes in data:
|
||||
assert_incompatible_shapes_raise(input_shapes)
|
||||
# Reverse the input shapes since broadcasting should be symmetric.
|
||||
assert_incompatible_shapes_raise(input_shapes[::-1])
|
||||
|
||||
|
||||
def test_same_as_ufunc():
|
||||
# Check that the data layout is the same as if a ufunc did the operation.
|
||||
|
||||
data = [
|
||||
[[(1,), (3,)], (3,)],
|
||||
[[(1, 3), (3, 3)], (3, 3)],
|
||||
[[(3, 1), (3, 3)], (3, 3)],
|
||||
[[(1, 3), (3, 1)], (3, 3)],
|
||||
[[(1, 1), (3, 3)], (3, 3)],
|
||||
[[(1, 1), (1, 3)], (1, 3)],
|
||||
[[(1, 1), (3, 1)], (3, 1)],
|
||||
[[(1, 0), (0, 0)], (0, 0)],
|
||||
[[(0, 1), (0, 0)], (0, 0)],
|
||||
[[(1, 0), (0, 1)], (0, 0)],
|
||||
[[(1, 1), (0, 0)], (0, 0)],
|
||||
[[(1, 1), (1, 0)], (1, 0)],
|
||||
[[(1, 1), (0, 1)], (0, 1)],
|
||||
[[(), (3,)], (3,)],
|
||||
[[(3,), (3, 3)], (3, 3)],
|
||||
[[(3,), (3, 1)], (3, 3)],
|
||||
[[(1,), (3, 3)], (3, 3)],
|
||||
[[(), (3, 3)], (3, 3)],
|
||||
[[(1, 1), (3,)], (1, 3)],
|
||||
[[(1,), (3, 1)], (3, 1)],
|
||||
[[(1,), (1, 3)], (1, 3)],
|
||||
[[(), (1, 3)], (1, 3)],
|
||||
[[(), (3, 1)], (3, 1)],
|
||||
[[(), (0,)], (0,)],
|
||||
[[(0,), (0, 0)], (0, 0)],
|
||||
[[(0,), (0, 1)], (0, 0)],
|
||||
[[(1,), (0, 0)], (0, 0)],
|
||||
[[(), (0, 0)], (0, 0)],
|
||||
[[(1, 1), (0,)], (1, 0)],
|
||||
[[(1,), (0, 1)], (0, 1)],
|
||||
[[(1,), (1, 0)], (1, 0)],
|
||||
[[(), (1, 0)], (1, 0)],
|
||||
[[(), (0, 1)], (0, 1)],
|
||||
]
|
||||
for input_shapes, expected_shape in data:
|
||||
assert_same_as_ufunc(input_shapes[0], input_shapes[1],
|
||||
"Shapes: %s %s" % (input_shapes[0], input_shapes[1]))
|
||||
# Reverse the input shapes since broadcasting should be symmetric.
|
||||
assert_same_as_ufunc(input_shapes[1], input_shapes[0])
|
||||
# Try them transposed, too.
|
||||
assert_same_as_ufunc(input_shapes[0], input_shapes[1], True)
|
||||
# ... and flipped for non-rank-0 inputs in order to test negative
|
||||
# strides.
|
||||
if () not in input_shapes:
|
||||
assert_same_as_ufunc(input_shapes[0], input_shapes[1], False, True)
|
||||
assert_same_as_ufunc(input_shapes[0], input_shapes[1], True, True)
|
||||
|
||||
|
||||
def test_broadcast_to_succeeds():
|
||||
data = [
|
||||
[np.array(0), (0,), np.array(0)],
|
||||
[np.array(0), (1,), np.zeros(1)],
|
||||
[np.array(0), (3,), np.zeros(3)],
|
||||
[np.ones(1), (1,), np.ones(1)],
|
||||
[np.ones(1), (2,), np.ones(2)],
|
||||
[np.ones(1), (1, 2, 3), np.ones((1, 2, 3))],
|
||||
[np.arange(3), (3,), np.arange(3)],
|
||||
[np.arange(3), (1, 3), np.arange(3).reshape(1, -1)],
|
||||
[np.arange(3), (2, 3), np.array([[0, 1, 2], [0, 1, 2]])],
|
||||
# test if shape is not a tuple
|
||||
[np.ones(0), 0, np.ones(0)],
|
||||
[np.ones(1), 1, np.ones(1)],
|
||||
[np.ones(1), 2, np.ones(2)],
|
||||
# these cases with size 0 are strange, but they reproduce the behavior
|
||||
# of broadcasting with ufuncs (see test_same_as_ufunc above)
|
||||
[np.ones(1), (0,), np.ones(0)],
|
||||
[np.ones((1, 2)), (0, 2), np.ones((0, 2))],
|
||||
[np.ones((2, 1)), (2, 0), np.ones((2, 0))],
|
||||
]
|
||||
for input_array, shape, expected in data:
|
||||
actual = broadcast_to(input_array, shape)
|
||||
assert_array_equal(expected, actual)
|
||||
|
||||
|
||||
def test_broadcast_to_raises():
|
||||
data = [
|
||||
[(0,), ()],
|
||||
[(1,), ()],
|
||||
[(3,), ()],
|
||||
[(3,), (1,)],
|
||||
[(3,), (2,)],
|
||||
[(3,), (4,)],
|
||||
[(1, 2), (2, 1)],
|
||||
[(1, 1), (1,)],
|
||||
[(1,), -1],
|
||||
[(1,), (-1,)],
|
||||
[(1, 2), (-1, 2)],
|
||||
]
|
||||
for orig_shape, target_shape in data:
|
||||
arr = np.zeros(orig_shape)
|
||||
assert_raises(ValueError, lambda: broadcast_to(arr, target_shape))
|
||||
|
||||
|
||||
def test_broadcast_shape():
|
||||
# broadcast_shape is already exercized indirectly by broadcast_arrays
|
||||
assert_equal(_broadcast_shape(), ())
|
||||
assert_equal(_broadcast_shape([1, 2]), (2,))
|
||||
assert_equal(_broadcast_shape(np.ones((1, 1))), (1, 1))
|
||||
assert_equal(_broadcast_shape(np.ones((1, 1)), np.ones((3, 4))), (3, 4))
|
||||
assert_equal(_broadcast_shape(*([np.ones((1, 2))] * 32)), (1, 2))
|
||||
assert_equal(_broadcast_shape(*([np.ones((1, 2))] * 100)), (1, 2))
|
||||
|
||||
# regression tests for gh-5862
|
||||
assert_equal(_broadcast_shape(*([np.ones(2)] * 32 + [1])), (2,))
|
||||
bad_args = [np.ones(2)] * 32 + [np.ones(3)] * 32
|
||||
assert_raises(ValueError, lambda: _broadcast_shape(*bad_args))
|
||||
|
||||
|
||||
def test_as_strided():
|
||||
a = np.array([None])
|
||||
a_view = as_strided(a)
|
||||
expected = np.array([None])
|
||||
assert_array_equal(a_view, np.array([None]))
|
||||
|
||||
a = np.array([1, 2, 3, 4])
|
||||
a_view = as_strided(a, shape=(2,), strides=(2 * a.itemsize,))
|
||||
expected = np.array([1, 3])
|
||||
assert_array_equal(a_view, expected)
|
||||
|
||||
a = np.array([1, 2, 3, 4])
|
||||
a_view = as_strided(a, shape=(3, 4), strides=(0, 1 * a.itemsize))
|
||||
expected = np.array([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]])
|
||||
assert_array_equal(a_view, expected)
|
||||
|
||||
# Regression test for gh-5081
|
||||
dt = np.dtype([('num', 'i4'), ('obj', 'O')])
|
||||
a = np.empty((4,), dtype=dt)
|
||||
a['num'] = np.arange(1, 5)
|
||||
a_view = as_strided(a, shape=(3, 4), strides=(0, a.itemsize))
|
||||
expected_num = [[1, 2, 3, 4]] * 3
|
||||
expected_obj = [[None]*4]*3
|
||||
assert_equal(a_view.dtype, dt)
|
||||
assert_array_equal(expected_num, a_view['num'])
|
||||
assert_array_equal(expected_obj, a_view['obj'])
|
||||
|
||||
# Make sure that void types without fields are kept unchanged
|
||||
a = np.empty((4,), dtype='V4')
|
||||
a_view = as_strided(a, shape=(3, 4), strides=(0, a.itemsize))
|
||||
assert_equal(a.dtype, a_view.dtype)
|
||||
|
||||
# Make sure that the only type that could fail is properly handled
|
||||
dt = np.dtype({'names': [''], 'formats': ['V4']})
|
||||
a = np.empty((4,), dtype=dt)
|
||||
a_view = as_strided(a, shape=(3, 4), strides=(0, a.itemsize))
|
||||
assert_equal(a.dtype, a_view.dtype)
|
||||
|
||||
# Custom dtypes should not be lost (gh-9161)
|
||||
r = [rational(i) for i in range(4)]
|
||||
a = np.array(r, dtype=rational)
|
||||
a_view = as_strided(a, shape=(3, 4), strides=(0, a.itemsize))
|
||||
assert_equal(a.dtype, a_view.dtype)
|
||||
assert_array_equal([r] * 3, a_view)
|
||||
|
||||
def as_strided_writeable():
|
||||
arr = np.ones(10)
|
||||
view = as_strided(arr, writeable=False)
|
||||
assert_(not view.flags.writeable)
|
||||
|
||||
# Check that writeable also is fine:
|
||||
view = as_strided(arr, writeable=True)
|
||||
assert_(view.flags.writeable)
|
||||
view[...] = 3
|
||||
assert_array_equal(arr, np.full_like(arr, 3))
|
||||
|
||||
# Test that things do not break down for readonly:
|
||||
arr.flags.writeable = False
|
||||
view = as_strided(arr, writeable=False)
|
||||
view = as_strided(arr, writeable=True)
|
||||
assert_(not view.flags.writeable)
|
||||
|
||||
|
||||
class VerySimpleSubClass(np.ndarray):
|
||||
def __new__(cls, *args, **kwargs):
|
||||
kwargs['subok'] = True
|
||||
return np.array(*args, **kwargs).view(cls)
|
||||
|
||||
|
||||
class SimpleSubClass(VerySimpleSubClass):
|
||||
def __new__(cls, *args, **kwargs):
|
||||
kwargs['subok'] = True
|
||||
self = np.array(*args, **kwargs).view(cls)
|
||||
self.info = 'simple'
|
||||
return self
|
||||
|
||||
def __array_finalize__(self, obj):
|
||||
self.info = getattr(obj, 'info', '') + ' finalized'
|
||||
|
||||
|
||||
def test_subclasses():
|
||||
# test that subclass is preserved only if subok=True
|
||||
a = VerySimpleSubClass([1, 2, 3, 4])
|
||||
assert_(type(a) is VerySimpleSubClass)
|
||||
a_view = as_strided(a, shape=(2,), strides=(2 * a.itemsize,))
|
||||
assert_(type(a_view) is np.ndarray)
|
||||
a_view = as_strided(a, shape=(2,), strides=(2 * a.itemsize,), subok=True)
|
||||
assert_(type(a_view) is VerySimpleSubClass)
|
||||
# test that if a subclass has __array_finalize__, it is used
|
||||
a = SimpleSubClass([1, 2, 3, 4])
|
||||
a_view = as_strided(a, shape=(2,), strides=(2 * a.itemsize,), subok=True)
|
||||
assert_(type(a_view) is SimpleSubClass)
|
||||
assert_(a_view.info == 'simple finalized')
|
||||
|
||||
# similar tests for broadcast_arrays
|
||||
b = np.arange(len(a)).reshape(-1, 1)
|
||||
a_view, b_view = broadcast_arrays(a, b)
|
||||
assert_(type(a_view) is np.ndarray)
|
||||
assert_(type(b_view) is np.ndarray)
|
||||
assert_(a_view.shape == b_view.shape)
|
||||
a_view, b_view = broadcast_arrays(a, b, subok=True)
|
||||
assert_(type(a_view) is SimpleSubClass)
|
||||
assert_(a_view.info == 'simple finalized')
|
||||
assert_(type(b_view) is np.ndarray)
|
||||
assert_(a_view.shape == b_view.shape)
|
||||
|
||||
# and for broadcast_to
|
||||
shape = (2, 4)
|
||||
a_view = broadcast_to(a, shape)
|
||||
assert_(type(a_view) is np.ndarray)
|
||||
assert_(a_view.shape == shape)
|
||||
a_view = broadcast_to(a, shape, subok=True)
|
||||
assert_(type(a_view) is SimpleSubClass)
|
||||
assert_(a_view.info == 'simple finalized')
|
||||
assert_(a_view.shape == shape)
|
||||
|
||||
|
||||
def test_writeable():
|
||||
# broadcast_to should return a readonly array
|
||||
original = np.array([1, 2, 3])
|
||||
result = broadcast_to(original, (2, 3))
|
||||
assert_equal(result.flags.writeable, False)
|
||||
assert_raises(ValueError, result.__setitem__, slice(None), 0)
|
||||
|
||||
# but the result of broadcast_arrays needs to be writeable (for now), to
|
||||
# preserve backwards compatibility
|
||||
for results in [broadcast_arrays(original),
|
||||
broadcast_arrays(0, original)]:
|
||||
for result in results:
|
||||
assert_equal(result.flags.writeable, True)
|
||||
# keep readonly input readonly
|
||||
original.flags.writeable = False
|
||||
_, result = broadcast_arrays(0, original)
|
||||
assert_equal(result.flags.writeable, False)
|
||||
|
||||
# regression test for GH6491
|
||||
shape = (2,)
|
||||
strides = [0]
|
||||
tricky_array = as_strided(np.array(0), shape, strides)
|
||||
other = np.zeros((1,))
|
||||
first, second = broadcast_arrays(tricky_array, other)
|
||||
assert_(first.shape == second.shape)
|
||||
|
||||
|
||||
def test_reference_types():
|
||||
input_array = np.array('a', dtype=object)
|
||||
expected = np.array(['a'] * 3, dtype=object)
|
||||
actual = broadcast_to(input_array, (3,))
|
||||
assert_array_equal(expected, actual)
|
||||
|
||||
actual, _ = broadcast_arrays(input_array, np.ones(3))
|
||||
assert_array_equal(expected, actual)
|
||||
@@ -0,0 +1,510 @@
|
||||
"""Test functions for matrix module
|
||||
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
from numpy.testing import (
|
||||
assert_equal, assert_array_equal, assert_array_max_ulp,
|
||||
assert_array_almost_equal, assert_raises,
|
||||
)
|
||||
|
||||
from numpy import (
|
||||
arange, add, fliplr, flipud, zeros, ones, eye, array, diag, histogram2d,
|
||||
tri, mask_indices, triu_indices, triu_indices_from, tril_indices,
|
||||
tril_indices_from, vander,
|
||||
)
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def get_mat(n):
|
||||
data = arange(n)
|
||||
data = add.outer(data, data)
|
||||
return data
|
||||
|
||||
|
||||
class TestEye(object):
|
||||
def test_basic(self):
|
||||
assert_equal(eye(4),
|
||||
array([[1, 0, 0, 0],
|
||||
[0, 1, 0, 0],
|
||||
[0, 0, 1, 0],
|
||||
[0, 0, 0, 1]]))
|
||||
|
||||
assert_equal(eye(4, dtype='f'),
|
||||
array([[1, 0, 0, 0],
|
||||
[0, 1, 0, 0],
|
||||
[0, 0, 1, 0],
|
||||
[0, 0, 0, 1]], 'f'))
|
||||
|
||||
assert_equal(eye(3) == 1,
|
||||
eye(3, dtype=bool))
|
||||
|
||||
def test_diag(self):
|
||||
assert_equal(eye(4, k=1),
|
||||
array([[0, 1, 0, 0],
|
||||
[0, 0, 1, 0],
|
||||
[0, 0, 0, 1],
|
||||
[0, 0, 0, 0]]))
|
||||
|
||||
assert_equal(eye(4, k=-1),
|
||||
array([[0, 0, 0, 0],
|
||||
[1, 0, 0, 0],
|
||||
[0, 1, 0, 0],
|
||||
[0, 0, 1, 0]]))
|
||||
|
||||
def test_2d(self):
|
||||
assert_equal(eye(4, 3),
|
||||
array([[1, 0, 0],
|
||||
[0, 1, 0],
|
||||
[0, 0, 1],
|
||||
[0, 0, 0]]))
|
||||
|
||||
assert_equal(eye(3, 4),
|
||||
array([[1, 0, 0, 0],
|
||||
[0, 1, 0, 0],
|
||||
[0, 0, 1, 0]]))
|
||||
|
||||
def test_diag2d(self):
|
||||
assert_equal(eye(3, 4, k=2),
|
||||
array([[0, 0, 1, 0],
|
||||
[0, 0, 0, 1],
|
||||
[0, 0, 0, 0]]))
|
||||
|
||||
assert_equal(eye(4, 3, k=-2),
|
||||
array([[0, 0, 0],
|
||||
[0, 0, 0],
|
||||
[1, 0, 0],
|
||||
[0, 1, 0]]))
|
||||
|
||||
def test_eye_bounds(self):
|
||||
assert_equal(eye(2, 2, 1), [[0, 1], [0, 0]])
|
||||
assert_equal(eye(2, 2, -1), [[0, 0], [1, 0]])
|
||||
assert_equal(eye(2, 2, 2), [[0, 0], [0, 0]])
|
||||
assert_equal(eye(2, 2, -2), [[0, 0], [0, 0]])
|
||||
assert_equal(eye(3, 2, 2), [[0, 0], [0, 0], [0, 0]])
|
||||
assert_equal(eye(3, 2, 1), [[0, 1], [0, 0], [0, 0]])
|
||||
assert_equal(eye(3, 2, -1), [[0, 0], [1, 0], [0, 1]])
|
||||
assert_equal(eye(3, 2, -2), [[0, 0], [0, 0], [1, 0]])
|
||||
assert_equal(eye(3, 2, -3), [[0, 0], [0, 0], [0, 0]])
|
||||
|
||||
def test_strings(self):
|
||||
assert_equal(eye(2, 2, dtype='S3'),
|
||||
[[b'1', b''], [b'', b'1']])
|
||||
|
||||
def test_bool(self):
|
||||
assert_equal(eye(2, 2, dtype=bool), [[True, False], [False, True]])
|
||||
|
||||
def test_order(self):
|
||||
mat_c = eye(4, 3, k=-1)
|
||||
mat_f = eye(4, 3, k=-1, order='F')
|
||||
assert_equal(mat_c, mat_f)
|
||||
assert mat_c.flags.c_contiguous
|
||||
assert not mat_c.flags.f_contiguous
|
||||
assert not mat_f.flags.c_contiguous
|
||||
assert mat_f.flags.f_contiguous
|
||||
|
||||
|
||||
class TestDiag(object):
|
||||
def test_vector(self):
|
||||
vals = (100 * arange(5)).astype('l')
|
||||
b = zeros((5, 5))
|
||||
for k in range(5):
|
||||
b[k, k] = vals[k]
|
||||
assert_equal(diag(vals), b)
|
||||
b = zeros((7, 7))
|
||||
c = b.copy()
|
||||
for k in range(5):
|
||||
b[k, k + 2] = vals[k]
|
||||
c[k + 2, k] = vals[k]
|
||||
assert_equal(diag(vals, k=2), b)
|
||||
assert_equal(diag(vals, k=-2), c)
|
||||
|
||||
def test_matrix(self, vals=None):
|
||||
if vals is None:
|
||||
vals = (100 * get_mat(5) + 1).astype('l')
|
||||
b = zeros((5,))
|
||||
for k in range(5):
|
||||
b[k] = vals[k, k]
|
||||
assert_equal(diag(vals), b)
|
||||
b = b * 0
|
||||
for k in range(3):
|
||||
b[k] = vals[k, k + 2]
|
||||
assert_equal(diag(vals, 2), b[:3])
|
||||
for k in range(3):
|
||||
b[k] = vals[k + 2, k]
|
||||
assert_equal(diag(vals, -2), b[:3])
|
||||
|
||||
def test_fortran_order(self):
|
||||
vals = array((100 * get_mat(5) + 1), order='F', dtype='l')
|
||||
self.test_matrix(vals)
|
||||
|
||||
def test_diag_bounds(self):
|
||||
A = [[1, 2], [3, 4], [5, 6]]
|
||||
assert_equal(diag(A, k=2), [])
|
||||
assert_equal(diag(A, k=1), [2])
|
||||
assert_equal(diag(A, k=0), [1, 4])
|
||||
assert_equal(diag(A, k=-1), [3, 6])
|
||||
assert_equal(diag(A, k=-2), [5])
|
||||
assert_equal(diag(A, k=-3), [])
|
||||
|
||||
def test_failure(self):
|
||||
assert_raises(ValueError, diag, [[[1]]])
|
||||
|
||||
|
||||
class TestFliplr(object):
|
||||
def test_basic(self):
|
||||
assert_raises(ValueError, fliplr, ones(4))
|
||||
a = get_mat(4)
|
||||
b = a[:, ::-1]
|
||||
assert_equal(fliplr(a), b)
|
||||
a = [[0, 1, 2],
|
||||
[3, 4, 5]]
|
||||
b = [[2, 1, 0],
|
||||
[5, 4, 3]]
|
||||
assert_equal(fliplr(a), b)
|
||||
|
||||
|
||||
class TestFlipud(object):
|
||||
def test_basic(self):
|
||||
a = get_mat(4)
|
||||
b = a[::-1, :]
|
||||
assert_equal(flipud(a), b)
|
||||
a = [[0, 1, 2],
|
||||
[3, 4, 5]]
|
||||
b = [[3, 4, 5],
|
||||
[0, 1, 2]]
|
||||
assert_equal(flipud(a), b)
|
||||
|
||||
|
||||
class TestHistogram2d(object):
|
||||
def test_simple(self):
|
||||
x = array(
|
||||
[0.41702200, 0.72032449, 1.1437481e-4, 0.302332573, 0.146755891])
|
||||
y = array(
|
||||
[0.09233859, 0.18626021, 0.34556073, 0.39676747, 0.53881673])
|
||||
xedges = np.linspace(0, 1, 10)
|
||||
yedges = np.linspace(0, 1, 10)
|
||||
H = histogram2d(x, y, (xedges, yedges))[0]
|
||||
answer = array(
|
||||
[[0, 0, 0, 1, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[1, 0, 1, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0]])
|
||||
assert_array_equal(H.T, answer)
|
||||
H = histogram2d(x, y, xedges)[0]
|
||||
assert_array_equal(H.T, answer)
|
||||
H, xedges, yedges = histogram2d(list(range(10)), list(range(10)))
|
||||
assert_array_equal(H, eye(10, 10))
|
||||
assert_array_equal(xedges, np.linspace(0, 9, 11))
|
||||
assert_array_equal(yedges, np.linspace(0, 9, 11))
|
||||
|
||||
def test_asym(self):
|
||||
x = array([1, 1, 2, 3, 4, 4, 4, 5])
|
||||
y = array([1, 3, 2, 0, 1, 2, 3, 4])
|
||||
H, xed, yed = histogram2d(
|
||||
x, y, (6, 5), range=[[0, 6], [0, 5]], density=True)
|
||||
answer = array(
|
||||
[[0., 0, 0, 0, 0],
|
||||
[0, 1, 0, 1, 0],
|
||||
[0, 0, 1, 0, 0],
|
||||
[1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 1]])
|
||||
assert_array_almost_equal(H, answer/8., 3)
|
||||
assert_array_equal(xed, np.linspace(0, 6, 7))
|
||||
assert_array_equal(yed, np.linspace(0, 5, 6))
|
||||
|
||||
def test_density(self):
|
||||
x = array([1, 2, 3, 1, 2, 3, 1, 2, 3])
|
||||
y = array([1, 1, 1, 2, 2, 2, 3, 3, 3])
|
||||
H, xed, yed = histogram2d(
|
||||
x, y, [[1, 2, 3, 5], [1, 2, 3, 5]], density=True)
|
||||
answer = array([[1, 1, .5],
|
||||
[1, 1, .5],
|
||||
[.5, .5, .25]])/9.
|
||||
assert_array_almost_equal(H, answer, 3)
|
||||
|
||||
def test_all_outliers(self):
|
||||
r = np.random.rand(100) + 1. + 1e6 # histogramdd rounds by decimal=6
|
||||
H, xed, yed = histogram2d(r, r, (4, 5), range=([0, 1], [0, 1]))
|
||||
assert_array_equal(H, 0)
|
||||
|
||||
def test_empty(self):
|
||||
a, edge1, edge2 = histogram2d([], [], bins=([0, 1], [0, 1]))
|
||||
assert_array_max_ulp(a, array([[0.]]))
|
||||
|
||||
a, edge1, edge2 = histogram2d([], [], bins=4)
|
||||
assert_array_max_ulp(a, np.zeros((4, 4)))
|
||||
|
||||
def test_binparameter_combination(self):
|
||||
x = array(
|
||||
[0, 0.09207008, 0.64575234, 0.12875982, 0.47390599,
|
||||
0.59944483, 1])
|
||||
y = array(
|
||||
[0, 0.14344267, 0.48988575, 0.30558665, 0.44700682,
|
||||
0.15886423, 1])
|
||||
edges = (0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1)
|
||||
H, xe, ye = histogram2d(x, y, (edges, 4))
|
||||
answer = array(
|
||||
[[2., 0., 0., 0.],
|
||||
[0., 1., 0., 0.],
|
||||
[0., 0., 0., 0.],
|
||||
[0., 0., 0., 0.],
|
||||
[0., 1., 0., 0.],
|
||||
[1., 0., 0., 0.],
|
||||
[0., 1., 0., 0.],
|
||||
[0., 0., 0., 0.],
|
||||
[0., 0., 0., 0.],
|
||||
[0., 0., 0., 1.]])
|
||||
assert_array_equal(H, answer)
|
||||
assert_array_equal(ye, array([0., 0.25, 0.5, 0.75, 1]))
|
||||
H, xe, ye = histogram2d(x, y, (4, edges))
|
||||
answer = array(
|
||||
[[1., 1., 0., 1., 0., 0., 0., 0., 0., 0.],
|
||||
[0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],
|
||||
[0., 1., 0., 0., 1., 0., 0., 0., 0., 0.],
|
||||
[0., 0., 0., 0., 0., 0., 0., 0., 0., 1.]])
|
||||
assert_array_equal(H, answer)
|
||||
assert_array_equal(xe, array([0., 0.25, 0.5, 0.75, 1]))
|
||||
|
||||
|
||||
class TestTri(object):
|
||||
def test_dtype(self):
|
||||
out = array([[1, 0, 0],
|
||||
[1, 1, 0],
|
||||
[1, 1, 1]])
|
||||
assert_array_equal(tri(3), out)
|
||||
assert_array_equal(tri(3, dtype=bool), out.astype(bool))
|
||||
|
||||
|
||||
def test_tril_triu_ndim2():
|
||||
for dtype in np.typecodes['AllFloat'] + np.typecodes['AllInteger']:
|
||||
a = np.ones((2, 2), dtype=dtype)
|
||||
b = np.tril(a)
|
||||
c = np.triu(a)
|
||||
assert_array_equal(b, [[1, 0], [1, 1]])
|
||||
assert_array_equal(c, b.T)
|
||||
# should return the same dtype as the original array
|
||||
assert_equal(b.dtype, a.dtype)
|
||||
assert_equal(c.dtype, a.dtype)
|
||||
|
||||
|
||||
def test_tril_triu_ndim3():
|
||||
for dtype in np.typecodes['AllFloat'] + np.typecodes['AllInteger']:
|
||||
a = np.array([
|
||||
[[1, 1], [1, 1]],
|
||||
[[1, 1], [1, 0]],
|
||||
[[1, 1], [0, 0]],
|
||||
], dtype=dtype)
|
||||
a_tril_desired = np.array([
|
||||
[[1, 0], [1, 1]],
|
||||
[[1, 0], [1, 0]],
|
||||
[[1, 0], [0, 0]],
|
||||
], dtype=dtype)
|
||||
a_triu_desired = np.array([
|
||||
[[1, 1], [0, 1]],
|
||||
[[1, 1], [0, 0]],
|
||||
[[1, 1], [0, 0]],
|
||||
], dtype=dtype)
|
||||
a_triu_observed = np.triu(a)
|
||||
a_tril_observed = np.tril(a)
|
||||
assert_array_equal(a_triu_observed, a_triu_desired)
|
||||
assert_array_equal(a_tril_observed, a_tril_desired)
|
||||
assert_equal(a_triu_observed.dtype, a.dtype)
|
||||
assert_equal(a_tril_observed.dtype, a.dtype)
|
||||
|
||||
|
||||
def test_tril_triu_with_inf():
|
||||
# Issue 4859
|
||||
arr = np.array([[1, 1, np.inf],
|
||||
[1, 1, 1],
|
||||
[np.inf, 1, 1]])
|
||||
out_tril = np.array([[1, 0, 0],
|
||||
[1, 1, 0],
|
||||
[np.inf, 1, 1]])
|
||||
out_triu = out_tril.T
|
||||
assert_array_equal(np.triu(arr), out_triu)
|
||||
assert_array_equal(np.tril(arr), out_tril)
|
||||
|
||||
|
||||
def test_tril_triu_dtype():
|
||||
# Issue 4916
|
||||
# tril and triu should return the same dtype as input
|
||||
for c in np.typecodes['All']:
|
||||
if c == 'V':
|
||||
continue
|
||||
arr = np.zeros((3, 3), dtype=c)
|
||||
assert_equal(np.triu(arr).dtype, arr.dtype)
|
||||
assert_equal(np.tril(arr).dtype, arr.dtype)
|
||||
|
||||
# check special cases
|
||||
arr = np.array([['2001-01-01T12:00', '2002-02-03T13:56'],
|
||||
['2004-01-01T12:00', '2003-01-03T13:45']],
|
||||
dtype='datetime64')
|
||||
assert_equal(np.triu(arr).dtype, arr.dtype)
|
||||
assert_equal(np.tril(arr).dtype, arr.dtype)
|
||||
|
||||
arr = np.zeros((3,3), dtype='f4,f4')
|
||||
assert_equal(np.triu(arr).dtype, arr.dtype)
|
||||
assert_equal(np.tril(arr).dtype, arr.dtype)
|
||||
|
||||
|
||||
def test_mask_indices():
|
||||
# simple test without offset
|
||||
iu = mask_indices(3, np.triu)
|
||||
a = np.arange(9).reshape(3, 3)
|
||||
assert_array_equal(a[iu], array([0, 1, 2, 4, 5, 8]))
|
||||
# Now with an offset
|
||||
iu1 = mask_indices(3, np.triu, 1)
|
||||
assert_array_equal(a[iu1], array([1, 2, 5]))
|
||||
|
||||
|
||||
def test_tril_indices():
|
||||
# indices without and with offset
|
||||
il1 = tril_indices(4)
|
||||
il2 = tril_indices(4, k=2)
|
||||
il3 = tril_indices(4, m=5)
|
||||
il4 = tril_indices(4, k=2, m=5)
|
||||
|
||||
a = np.array([[1, 2, 3, 4],
|
||||
[5, 6, 7, 8],
|
||||
[9, 10, 11, 12],
|
||||
[13, 14, 15, 16]])
|
||||
b = np.arange(1, 21).reshape(4, 5)
|
||||
|
||||
# indexing:
|
||||
assert_array_equal(a[il1],
|
||||
array([1, 5, 6, 9, 10, 11, 13, 14, 15, 16]))
|
||||
assert_array_equal(b[il3],
|
||||
array([1, 6, 7, 11, 12, 13, 16, 17, 18, 19]))
|
||||
|
||||
# And for assigning values:
|
||||
a[il1] = -1
|
||||
assert_array_equal(a,
|
||||
array([[-1, 2, 3, 4],
|
||||
[-1, -1, 7, 8],
|
||||
[-1, -1, -1, 12],
|
||||
[-1, -1, -1, -1]]))
|
||||
b[il3] = -1
|
||||
assert_array_equal(b,
|
||||
array([[-1, 2, 3, 4, 5],
|
||||
[-1, -1, 8, 9, 10],
|
||||
[-1, -1, -1, 14, 15],
|
||||
[-1, -1, -1, -1, 20]]))
|
||||
# These cover almost the whole array (two diagonals right of the main one):
|
||||
a[il2] = -10
|
||||
assert_array_equal(a,
|
||||
array([[-10, -10, -10, 4],
|
||||
[-10, -10, -10, -10],
|
||||
[-10, -10, -10, -10],
|
||||
[-10, -10, -10, -10]]))
|
||||
b[il4] = -10
|
||||
assert_array_equal(b,
|
||||
array([[-10, -10, -10, 4, 5],
|
||||
[-10, -10, -10, -10, 10],
|
||||
[-10, -10, -10, -10, -10],
|
||||
[-10, -10, -10, -10, -10]]))
|
||||
|
||||
|
||||
class TestTriuIndices(object):
|
||||
def test_triu_indices(self):
|
||||
iu1 = triu_indices(4)
|
||||
iu2 = triu_indices(4, k=2)
|
||||
iu3 = triu_indices(4, m=5)
|
||||
iu4 = triu_indices(4, k=2, m=5)
|
||||
|
||||
a = np.array([[1, 2, 3, 4],
|
||||
[5, 6, 7, 8],
|
||||
[9, 10, 11, 12],
|
||||
[13, 14, 15, 16]])
|
||||
b = np.arange(1, 21).reshape(4, 5)
|
||||
|
||||
# Both for indexing:
|
||||
assert_array_equal(a[iu1],
|
||||
array([1, 2, 3, 4, 6, 7, 8, 11, 12, 16]))
|
||||
assert_array_equal(b[iu3],
|
||||
array([1, 2, 3, 4, 5, 7, 8, 9,
|
||||
10, 13, 14, 15, 19, 20]))
|
||||
|
||||
# And for assigning values:
|
||||
a[iu1] = -1
|
||||
assert_array_equal(a,
|
||||
array([[-1, -1, -1, -1],
|
||||
[5, -1, -1, -1],
|
||||
[9, 10, -1, -1],
|
||||
[13, 14, 15, -1]]))
|
||||
b[iu3] = -1
|
||||
assert_array_equal(b,
|
||||
array([[-1, -1, -1, -1, -1],
|
||||
[6, -1, -1, -1, -1],
|
||||
[11, 12, -1, -1, -1],
|
||||
[16, 17, 18, -1, -1]]))
|
||||
|
||||
# These cover almost the whole array (two diagonals right of the
|
||||
# main one):
|
||||
a[iu2] = -10
|
||||
assert_array_equal(a,
|
||||
array([[-1, -1, -10, -10],
|
||||
[5, -1, -1, -10],
|
||||
[9, 10, -1, -1],
|
||||
[13, 14, 15, -1]]))
|
||||
b[iu4] = -10
|
||||
assert_array_equal(b,
|
||||
array([[-1, -1, -10, -10, -10],
|
||||
[6, -1, -1, -10, -10],
|
||||
[11, 12, -1, -1, -10],
|
||||
[16, 17, 18, -1, -1]]))
|
||||
|
||||
|
||||
class TestTrilIndicesFrom(object):
|
||||
def test_exceptions(self):
|
||||
assert_raises(ValueError, tril_indices_from, np.ones((2,)))
|
||||
assert_raises(ValueError, tril_indices_from, np.ones((2, 2, 2)))
|
||||
# assert_raises(ValueError, tril_indices_from, np.ones((2, 3)))
|
||||
|
||||
|
||||
class TestTriuIndicesFrom(object):
|
||||
def test_exceptions(self):
|
||||
assert_raises(ValueError, triu_indices_from, np.ones((2,)))
|
||||
assert_raises(ValueError, triu_indices_from, np.ones((2, 2, 2)))
|
||||
# assert_raises(ValueError, triu_indices_from, np.ones((2, 3)))
|
||||
|
||||
|
||||
class TestVander(object):
|
||||
def test_basic(self):
|
||||
c = np.array([0, 1, -2, 3])
|
||||
v = vander(c)
|
||||
powers = np.array([[0, 0, 0, 0, 1],
|
||||
[1, 1, 1, 1, 1],
|
||||
[16, -8, 4, -2, 1],
|
||||
[81, 27, 9, 3, 1]])
|
||||
# Check default value of N:
|
||||
assert_array_equal(v, powers[:, 1:])
|
||||
# Check a range of N values, including 0 and 5 (greater than default)
|
||||
m = powers.shape[1]
|
||||
for n in range(6):
|
||||
v = vander(c, N=n)
|
||||
assert_array_equal(v, powers[:, m-n:m])
|
||||
|
||||
def test_dtypes(self):
|
||||
c = array([11, -12, 13], dtype=np.int8)
|
||||
v = vander(c)
|
||||
expected = np.array([[121, 11, 1],
|
||||
[144, -12, 1],
|
||||
[169, 13, 1]])
|
||||
assert_array_equal(v, expected)
|
||||
|
||||
c = array([1.0+1j, 1.0-1j])
|
||||
v = vander(c, N=3)
|
||||
expected = np.array([[2j, 1+1j, 1],
|
||||
[-2j, 1-1j, 1]])
|
||||
# The data is floating point, but the values are small integers,
|
||||
# so assert_array_equal *should* be safe here (rather than, say,
|
||||
# assert_array_almost_equal).
|
||||
assert_array_equal(v, expected)
|
||||
@@ -0,0 +1,442 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import numpy as np
|
||||
from numpy.compat import long
|
||||
from numpy.testing import (
|
||||
assert_, assert_equal, assert_array_equal, assert_raises
|
||||
)
|
||||
from numpy.lib.type_check import (
|
||||
common_type, mintypecode, isreal, iscomplex, isposinf, isneginf,
|
||||
nan_to_num, isrealobj, iscomplexobj, asfarray, real_if_close
|
||||
)
|
||||
|
||||
|
||||
def assert_all(x):
|
||||
assert_(np.all(x), x)
|
||||
|
||||
|
||||
class TestCommonType(object):
|
||||
def test_basic(self):
|
||||
ai32 = np.array([[1, 2], [3, 4]], dtype=np.int32)
|
||||
af16 = np.array([[1, 2], [3, 4]], dtype=np.float16)
|
||||
af32 = np.array([[1, 2], [3, 4]], dtype=np.float32)
|
||||
af64 = np.array([[1, 2], [3, 4]], dtype=np.float64)
|
||||
acs = np.array([[1+5j, 2+6j], [3+7j, 4+8j]], dtype=np.csingle)
|
||||
acd = np.array([[1+5j, 2+6j], [3+7j, 4+8j]], dtype=np.cdouble)
|
||||
assert_(common_type(ai32) == np.float64)
|
||||
assert_(common_type(af16) == np.float16)
|
||||
assert_(common_type(af32) == np.float32)
|
||||
assert_(common_type(af64) == np.float64)
|
||||
assert_(common_type(acs) == np.csingle)
|
||||
assert_(common_type(acd) == np.cdouble)
|
||||
|
||||
|
||||
class TestMintypecode(object):
|
||||
|
||||
def test_default_1(self):
|
||||
for itype in '1bcsuwil':
|
||||
assert_equal(mintypecode(itype), 'd')
|
||||
assert_equal(mintypecode('f'), 'f')
|
||||
assert_equal(mintypecode('d'), 'd')
|
||||
assert_equal(mintypecode('F'), 'F')
|
||||
assert_equal(mintypecode('D'), 'D')
|
||||
|
||||
def test_default_2(self):
|
||||
for itype in '1bcsuwil':
|
||||
assert_equal(mintypecode(itype+'f'), 'f')
|
||||
assert_equal(mintypecode(itype+'d'), 'd')
|
||||
assert_equal(mintypecode(itype+'F'), 'F')
|
||||
assert_equal(mintypecode(itype+'D'), 'D')
|
||||
assert_equal(mintypecode('ff'), 'f')
|
||||
assert_equal(mintypecode('fd'), 'd')
|
||||
assert_equal(mintypecode('fF'), 'F')
|
||||
assert_equal(mintypecode('fD'), 'D')
|
||||
assert_equal(mintypecode('df'), 'd')
|
||||
assert_equal(mintypecode('dd'), 'd')
|
||||
#assert_equal(mintypecode('dF',savespace=1),'F')
|
||||
assert_equal(mintypecode('dF'), 'D')
|
||||
assert_equal(mintypecode('dD'), 'D')
|
||||
assert_equal(mintypecode('Ff'), 'F')
|
||||
#assert_equal(mintypecode('Fd',savespace=1),'F')
|
||||
assert_equal(mintypecode('Fd'), 'D')
|
||||
assert_equal(mintypecode('FF'), 'F')
|
||||
assert_equal(mintypecode('FD'), 'D')
|
||||
assert_equal(mintypecode('Df'), 'D')
|
||||
assert_equal(mintypecode('Dd'), 'D')
|
||||
assert_equal(mintypecode('DF'), 'D')
|
||||
assert_equal(mintypecode('DD'), 'D')
|
||||
|
||||
def test_default_3(self):
|
||||
assert_equal(mintypecode('fdF'), 'D')
|
||||
#assert_equal(mintypecode('fdF',savespace=1),'F')
|
||||
assert_equal(mintypecode('fdD'), 'D')
|
||||
assert_equal(mintypecode('fFD'), 'D')
|
||||
assert_equal(mintypecode('dFD'), 'D')
|
||||
|
||||
assert_equal(mintypecode('ifd'), 'd')
|
||||
assert_equal(mintypecode('ifF'), 'F')
|
||||
assert_equal(mintypecode('ifD'), 'D')
|
||||
assert_equal(mintypecode('idF'), 'D')
|
||||
#assert_equal(mintypecode('idF',savespace=1),'F')
|
||||
assert_equal(mintypecode('idD'), 'D')
|
||||
|
||||
|
||||
class TestIsscalar(object):
|
||||
|
||||
def test_basic(self):
|
||||
assert_(np.isscalar(3))
|
||||
assert_(not np.isscalar([3]))
|
||||
assert_(not np.isscalar((3,)))
|
||||
assert_(np.isscalar(3j))
|
||||
assert_(np.isscalar(long(10)))
|
||||
assert_(np.isscalar(4.0))
|
||||
|
||||
|
||||
class TestReal(object):
|
||||
|
||||
def test_real(self):
|
||||
y = np.random.rand(10,)
|
||||
assert_array_equal(y, np.real(y))
|
||||
|
||||
y = np.array(1)
|
||||
out = np.real(y)
|
||||
assert_array_equal(y, out)
|
||||
assert_(isinstance(out, np.ndarray))
|
||||
|
||||
y = 1
|
||||
out = np.real(y)
|
||||
assert_equal(y, out)
|
||||
assert_(not isinstance(out, np.ndarray))
|
||||
|
||||
def test_cmplx(self):
|
||||
y = np.random.rand(10,)+1j*np.random.rand(10,)
|
||||
assert_array_equal(y.real, np.real(y))
|
||||
|
||||
y = np.array(1 + 1j)
|
||||
out = np.real(y)
|
||||
assert_array_equal(y.real, out)
|
||||
assert_(isinstance(out, np.ndarray))
|
||||
|
||||
y = 1 + 1j
|
||||
out = np.real(y)
|
||||
assert_equal(1.0, out)
|
||||
assert_(not isinstance(out, np.ndarray))
|
||||
|
||||
|
||||
class TestImag(object):
|
||||
|
||||
def test_real(self):
|
||||
y = np.random.rand(10,)
|
||||
assert_array_equal(0, np.imag(y))
|
||||
|
||||
y = np.array(1)
|
||||
out = np.imag(y)
|
||||
assert_array_equal(0, out)
|
||||
assert_(isinstance(out, np.ndarray))
|
||||
|
||||
y = 1
|
||||
out = np.imag(y)
|
||||
assert_equal(0, out)
|
||||
assert_(not isinstance(out, np.ndarray))
|
||||
|
||||
def test_cmplx(self):
|
||||
y = np.random.rand(10,)+1j*np.random.rand(10,)
|
||||
assert_array_equal(y.imag, np.imag(y))
|
||||
|
||||
y = np.array(1 + 1j)
|
||||
out = np.imag(y)
|
||||
assert_array_equal(y.imag, out)
|
||||
assert_(isinstance(out, np.ndarray))
|
||||
|
||||
y = 1 + 1j
|
||||
out = np.imag(y)
|
||||
assert_equal(1.0, out)
|
||||
assert_(not isinstance(out, np.ndarray))
|
||||
|
||||
|
||||
class TestIscomplex(object):
|
||||
|
||||
def test_fail(self):
|
||||
z = np.array([-1, 0, 1])
|
||||
res = iscomplex(z)
|
||||
assert_(not np.sometrue(res, axis=0))
|
||||
|
||||
def test_pass(self):
|
||||
z = np.array([-1j, 1, 0])
|
||||
res = iscomplex(z)
|
||||
assert_array_equal(res, [1, 0, 0])
|
||||
|
||||
|
||||
class TestIsreal(object):
|
||||
|
||||
def test_pass(self):
|
||||
z = np.array([-1, 0, 1j])
|
||||
res = isreal(z)
|
||||
assert_array_equal(res, [1, 1, 0])
|
||||
|
||||
def test_fail(self):
|
||||
z = np.array([-1j, 1, 0])
|
||||
res = isreal(z)
|
||||
assert_array_equal(res, [0, 1, 1])
|
||||
|
||||
|
||||
class TestIscomplexobj(object):
|
||||
|
||||
def test_basic(self):
|
||||
z = np.array([-1, 0, 1])
|
||||
assert_(not iscomplexobj(z))
|
||||
z = np.array([-1j, 0, -1])
|
||||
assert_(iscomplexobj(z))
|
||||
|
||||
def test_scalar(self):
|
||||
assert_(not iscomplexobj(1.0))
|
||||
assert_(iscomplexobj(1+0j))
|
||||
|
||||
def test_list(self):
|
||||
assert_(iscomplexobj([3, 1+0j, True]))
|
||||
assert_(not iscomplexobj([3, 1, True]))
|
||||
|
||||
def test_duck(self):
|
||||
class DummyComplexArray:
|
||||
@property
|
||||
def dtype(self):
|
||||
return np.dtype(complex)
|
||||
dummy = DummyComplexArray()
|
||||
assert_(iscomplexobj(dummy))
|
||||
|
||||
def test_pandas_duck(self):
|
||||
# This tests a custom np.dtype duck-typed class, such as used by pandas
|
||||
# (pandas.core.dtypes)
|
||||
class PdComplex(np.complex128):
|
||||
pass
|
||||
class PdDtype(object):
|
||||
name = 'category'
|
||||
names = None
|
||||
type = PdComplex
|
||||
kind = 'c'
|
||||
str = '<c16'
|
||||
base = np.dtype('complex128')
|
||||
class DummyPd:
|
||||
@property
|
||||
def dtype(self):
|
||||
return PdDtype
|
||||
dummy = DummyPd()
|
||||
assert_(iscomplexobj(dummy))
|
||||
|
||||
def test_custom_dtype_duck(self):
|
||||
class MyArray(list):
|
||||
@property
|
||||
def dtype(self):
|
||||
return complex
|
||||
|
||||
a = MyArray([1+0j, 2+0j, 3+0j])
|
||||
assert_(iscomplexobj(a))
|
||||
|
||||
|
||||
class TestIsrealobj(object):
|
||||
def test_basic(self):
|
||||
z = np.array([-1, 0, 1])
|
||||
assert_(isrealobj(z))
|
||||
z = np.array([-1j, 0, -1])
|
||||
assert_(not isrealobj(z))
|
||||
|
||||
|
||||
class TestIsnan(object):
|
||||
|
||||
def test_goodvalues(self):
|
||||
z = np.array((-1., 0., 1.))
|
||||
res = np.isnan(z) == 0
|
||||
assert_all(np.all(res, axis=0))
|
||||
|
||||
def test_posinf(self):
|
||||
with np.errstate(divide='ignore'):
|
||||
assert_all(np.isnan(np.array((1.,))/0.) == 0)
|
||||
|
||||
def test_neginf(self):
|
||||
with np.errstate(divide='ignore'):
|
||||
assert_all(np.isnan(np.array((-1.,))/0.) == 0)
|
||||
|
||||
def test_ind(self):
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
assert_all(np.isnan(np.array((0.,))/0.) == 1)
|
||||
|
||||
def test_integer(self):
|
||||
assert_all(np.isnan(1) == 0)
|
||||
|
||||
def test_complex(self):
|
||||
assert_all(np.isnan(1+1j) == 0)
|
||||
|
||||
def test_complex1(self):
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
assert_all(np.isnan(np.array(0+0j)/0.) == 1)
|
||||
|
||||
|
||||
class TestIsfinite(object):
|
||||
# Fixme, wrong place, isfinite now ufunc
|
||||
|
||||
def test_goodvalues(self):
|
||||
z = np.array((-1., 0., 1.))
|
||||
res = np.isfinite(z) == 1
|
||||
assert_all(np.all(res, axis=0))
|
||||
|
||||
def test_posinf(self):
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
assert_all(np.isfinite(np.array((1.,))/0.) == 0)
|
||||
|
||||
def test_neginf(self):
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
assert_all(np.isfinite(np.array((-1.,))/0.) == 0)
|
||||
|
||||
def test_ind(self):
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
assert_all(np.isfinite(np.array((0.,))/0.) == 0)
|
||||
|
||||
def test_integer(self):
|
||||
assert_all(np.isfinite(1) == 1)
|
||||
|
||||
def test_complex(self):
|
||||
assert_all(np.isfinite(1+1j) == 1)
|
||||
|
||||
def test_complex1(self):
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
assert_all(np.isfinite(np.array(1+1j)/0.) == 0)
|
||||
|
||||
|
||||
class TestIsinf(object):
|
||||
# Fixme, wrong place, isinf now ufunc
|
||||
|
||||
def test_goodvalues(self):
|
||||
z = np.array((-1., 0., 1.))
|
||||
res = np.isinf(z) == 0
|
||||
assert_all(np.all(res, axis=0))
|
||||
|
||||
def test_posinf(self):
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
assert_all(np.isinf(np.array((1.,))/0.) == 1)
|
||||
|
||||
def test_posinf_scalar(self):
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
assert_all(np.isinf(np.array(1.,)/0.) == 1)
|
||||
|
||||
def test_neginf(self):
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
assert_all(np.isinf(np.array((-1.,))/0.) == 1)
|
||||
|
||||
def test_neginf_scalar(self):
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
assert_all(np.isinf(np.array(-1.)/0.) == 1)
|
||||
|
||||
def test_ind(self):
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
assert_all(np.isinf(np.array((0.,))/0.) == 0)
|
||||
|
||||
|
||||
class TestIsposinf(object):
|
||||
|
||||
def test_generic(self):
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
vals = isposinf(np.array((-1., 0, 1))/0.)
|
||||
assert_(vals[0] == 0)
|
||||
assert_(vals[1] == 0)
|
||||
assert_(vals[2] == 1)
|
||||
|
||||
|
||||
class TestIsneginf(object):
|
||||
|
||||
def test_generic(self):
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
vals = isneginf(np.array((-1., 0, 1))/0.)
|
||||
assert_(vals[0] == 1)
|
||||
assert_(vals[1] == 0)
|
||||
assert_(vals[2] == 0)
|
||||
|
||||
|
||||
class TestNanToNum(object):
|
||||
|
||||
def test_generic(self):
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
vals = nan_to_num(np.array((-1., 0, 1))/0.)
|
||||
assert_all(vals[0] < -1e10) and assert_all(np.isfinite(vals[0]))
|
||||
assert_(vals[1] == 0)
|
||||
assert_all(vals[2] > 1e10) and assert_all(np.isfinite(vals[2]))
|
||||
assert_equal(type(vals), np.ndarray)
|
||||
|
||||
# perform the same test but in-place
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
vals = np.array((-1., 0, 1))/0.
|
||||
result = nan_to_num(vals, copy=False)
|
||||
|
||||
assert_(result is vals)
|
||||
assert_all(vals[0] < -1e10) and assert_all(np.isfinite(vals[0]))
|
||||
assert_(vals[1] == 0)
|
||||
assert_all(vals[2] > 1e10) and assert_all(np.isfinite(vals[2]))
|
||||
assert_equal(type(vals), np.ndarray)
|
||||
|
||||
def test_array(self):
|
||||
vals = nan_to_num([1])
|
||||
assert_array_equal(vals, np.array([1], int))
|
||||
assert_equal(type(vals), np.ndarray)
|
||||
|
||||
def test_integer(self):
|
||||
vals = nan_to_num(1)
|
||||
assert_all(vals == 1)
|
||||
assert_equal(type(vals), np.int_)
|
||||
|
||||
def test_float(self):
|
||||
vals = nan_to_num(1.0)
|
||||
assert_all(vals == 1.0)
|
||||
assert_equal(type(vals), np.float_)
|
||||
|
||||
def test_complex_good(self):
|
||||
vals = nan_to_num(1+1j)
|
||||
assert_all(vals == 1+1j)
|
||||
assert_equal(type(vals), np.complex_)
|
||||
|
||||
def test_complex_bad(self):
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
v = 1 + 1j
|
||||
v += np.array(0+1.j)/0.
|
||||
vals = nan_to_num(v)
|
||||
# !! This is actually (unexpectedly) zero
|
||||
assert_all(np.isfinite(vals))
|
||||
assert_equal(type(vals), np.complex_)
|
||||
|
||||
def test_complex_bad2(self):
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
v = 1 + 1j
|
||||
v += np.array(-1+1.j)/0.
|
||||
vals = nan_to_num(v)
|
||||
assert_all(np.isfinite(vals))
|
||||
assert_equal(type(vals), np.complex_)
|
||||
# Fixme
|
||||
#assert_all(vals.imag > 1e10) and assert_all(np.isfinite(vals))
|
||||
# !! This is actually (unexpectedly) positive
|
||||
# !! inf. Comment out for now, and see if it
|
||||
# !! changes
|
||||
#assert_all(vals.real < -1e10) and assert_all(np.isfinite(vals))
|
||||
|
||||
|
||||
class TestRealIfClose(object):
|
||||
|
||||
def test_basic(self):
|
||||
a = np.random.rand(10)
|
||||
b = real_if_close(a+1e-15j)
|
||||
assert_all(isrealobj(b))
|
||||
assert_array_equal(a, b)
|
||||
b = real_if_close(a+1e-7j)
|
||||
assert_all(iscomplexobj(b))
|
||||
b = real_if_close(a+1e-7j, tol=1e-6)
|
||||
assert_all(isrealobj(b))
|
||||
|
||||
|
||||
class TestArrayConversion(object):
|
||||
|
||||
def test_asfarray(self):
|
||||
a = asfarray(np.array([1, 2, 3]))
|
||||
assert_equal(a.__class__, np.ndarray)
|
||||
assert_(np.issubdtype(a.dtype, np.floating))
|
||||
|
||||
# previously this would infer dtypes from arrays, unlike every single
|
||||
# other numpy function
|
||||
assert_raises(TypeError,
|
||||
asfarray, np.array([1, 2, 3]), dtype=np.array(1.0))
|
||||
@@ -0,0 +1,106 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import numpy as np
|
||||
import numpy.core as nx
|
||||
import numpy.lib.ufunclike as ufl
|
||||
from numpy.testing import (
|
||||
assert_, assert_equal, assert_array_equal, assert_warns, assert_raises
|
||||
)
|
||||
|
||||
|
||||
class TestUfunclike(object):
|
||||
|
||||
def test_isposinf(self):
|
||||
a = nx.array([nx.inf, -nx.inf, nx.nan, 0.0, 3.0, -3.0])
|
||||
out = nx.zeros(a.shape, bool)
|
||||
tgt = nx.array([True, False, False, False, False, False])
|
||||
|
||||
res = ufl.isposinf(a)
|
||||
assert_equal(res, tgt)
|
||||
res = ufl.isposinf(a, out)
|
||||
assert_equal(res, tgt)
|
||||
assert_equal(out, tgt)
|
||||
|
||||
a = a.astype(np.complex)
|
||||
with assert_raises(TypeError):
|
||||
ufl.isposinf(a)
|
||||
|
||||
def test_isneginf(self):
|
||||
a = nx.array([nx.inf, -nx.inf, nx.nan, 0.0, 3.0, -3.0])
|
||||
out = nx.zeros(a.shape, bool)
|
||||
tgt = nx.array([False, True, False, False, False, False])
|
||||
|
||||
res = ufl.isneginf(a)
|
||||
assert_equal(res, tgt)
|
||||
res = ufl.isneginf(a, out)
|
||||
assert_equal(res, tgt)
|
||||
assert_equal(out, tgt)
|
||||
|
||||
a = a.astype(np.complex)
|
||||
with assert_raises(TypeError):
|
||||
ufl.isneginf(a)
|
||||
|
||||
def test_fix(self):
|
||||
a = nx.array([[1.0, 1.1, 1.5, 1.8], [-1.0, -1.1, -1.5, -1.8]])
|
||||
out = nx.zeros(a.shape, float)
|
||||
tgt = nx.array([[1., 1., 1., 1.], [-1., -1., -1., -1.]])
|
||||
|
||||
res = ufl.fix(a)
|
||||
assert_equal(res, tgt)
|
||||
res = ufl.fix(a, out)
|
||||
assert_equal(res, tgt)
|
||||
assert_equal(out, tgt)
|
||||
assert_equal(ufl.fix(3.14), 3)
|
||||
|
||||
def test_fix_with_subclass(self):
|
||||
class MyArray(nx.ndarray):
|
||||
def __new__(cls, data, metadata=None):
|
||||
res = nx.array(data, copy=True).view(cls)
|
||||
res.metadata = metadata
|
||||
return res
|
||||
|
||||
def __array_wrap__(self, obj, context=None):
|
||||
if isinstance(obj, MyArray):
|
||||
obj.metadata = self.metadata
|
||||
return obj
|
||||
|
||||
def __array_finalize__(self, obj):
|
||||
self.metadata = getattr(obj, 'metadata', None)
|
||||
return self
|
||||
|
||||
a = nx.array([1.1, -1.1])
|
||||
m = MyArray(a, metadata='foo')
|
||||
f = ufl.fix(m)
|
||||
assert_array_equal(f, nx.array([1, -1]))
|
||||
assert_(isinstance(f, MyArray))
|
||||
assert_equal(f.metadata, 'foo')
|
||||
|
||||
# check 0d arrays don't decay to scalars
|
||||
m0d = m[0,...]
|
||||
m0d.metadata = 'bar'
|
||||
f0d = ufl.fix(m0d)
|
||||
assert_(isinstance(f0d, MyArray))
|
||||
assert_equal(f0d.metadata, 'bar')
|
||||
|
||||
def test_deprecated(self):
|
||||
# NumPy 1.13.0, 2017-04-26
|
||||
assert_warns(DeprecationWarning, ufl.fix, [1, 2], y=nx.empty(2))
|
||||
assert_warns(DeprecationWarning, ufl.isposinf, [1, 2], y=nx.empty(2))
|
||||
assert_warns(DeprecationWarning, ufl.isneginf, [1, 2], y=nx.empty(2))
|
||||
|
||||
def test_scalar(self):
|
||||
x = np.inf
|
||||
actual = np.isposinf(x)
|
||||
expected = np.True_
|
||||
assert_equal(actual, expected)
|
||||
assert_equal(type(actual), type(expected))
|
||||
|
||||
x = -3.4
|
||||
actual = np.fix(x)
|
||||
expected = np.float64(-3.0)
|
||||
assert_equal(actual, expected)
|
||||
assert_equal(type(actual), type(expected))
|
||||
|
||||
out = np.array(0.0)
|
||||
actual = np.fix(x, out=out)
|
||||
assert_(actual is out)
|
||||
@@ -0,0 +1,91 @@
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
from numpy.core import arange
|
||||
from numpy.testing import assert_, assert_equal, assert_raises_regex
|
||||
from numpy.lib import deprecate
|
||||
import numpy.lib.utils as utils
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
from io import StringIO
|
||||
else:
|
||||
from StringIO import StringIO
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.flags.optimize == 2, reason="Python running -OO")
|
||||
def test_lookfor():
|
||||
out = StringIO()
|
||||
utils.lookfor('eigenvalue', module='numpy', output=out,
|
||||
import_modules=False)
|
||||
out = out.getvalue()
|
||||
assert_('numpy.linalg.eig' in out)
|
||||
|
||||
|
||||
@deprecate
|
||||
def old_func(self, x):
|
||||
return x
|
||||
|
||||
|
||||
@deprecate(message="Rather use new_func2")
|
||||
def old_func2(self, x):
|
||||
return x
|
||||
|
||||
|
||||
def old_func3(self, x):
|
||||
return x
|
||||
new_func3 = deprecate(old_func3, old_name="old_func3", new_name="new_func3")
|
||||
|
||||
|
||||
def test_deprecate_decorator():
|
||||
assert_('deprecated' in old_func.__doc__)
|
||||
|
||||
|
||||
def test_deprecate_decorator_message():
|
||||
assert_('Rather use new_func2' in old_func2.__doc__)
|
||||
|
||||
|
||||
def test_deprecate_fn():
|
||||
assert_('old_func3' in new_func3.__doc__)
|
||||
assert_('new_func3' in new_func3.__doc__)
|
||||
|
||||
|
||||
def test_safe_eval_nameconstant():
|
||||
# Test if safe_eval supports Python 3.4 _ast.NameConstant
|
||||
utils.safe_eval('None')
|
||||
|
||||
|
||||
class TestByteBounds(object):
|
||||
|
||||
def test_byte_bounds(self):
|
||||
# pointer difference matches size * itemsize
|
||||
# due to contiguity
|
||||
a = arange(12).reshape(3, 4)
|
||||
low, high = utils.byte_bounds(a)
|
||||
assert_equal(high - low, a.size * a.itemsize)
|
||||
|
||||
def test_unusual_order_positive_stride(self):
|
||||
a = arange(12).reshape(3, 4)
|
||||
b = a.T
|
||||
low, high = utils.byte_bounds(b)
|
||||
assert_equal(high - low, b.size * b.itemsize)
|
||||
|
||||
def test_unusual_order_negative_stride(self):
|
||||
a = arange(12).reshape(3, 4)
|
||||
b = a.T[::-1]
|
||||
low, high = utils.byte_bounds(b)
|
||||
assert_equal(high - low, b.size * b.itemsize)
|
||||
|
||||
def test_strided(self):
|
||||
a = arange(12)
|
||||
b = a[::2]
|
||||
low, high = utils.byte_bounds(b)
|
||||
# the largest pointer address is lost (even numbers only in the
|
||||
# stride), and compensate addresses for striding by 2
|
||||
assert_equal(high - low, b.size * 2 * b.itemsize - b.itemsize)
|
||||
|
||||
|
||||
def test_assert_raises_regex_context_manager():
|
||||
with assert_raises_regex(ValueError, 'no deprecation warning'):
|
||||
raise ValueError('no deprecation warning')
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,698 @@
|
||||
"""Automatically adapted for numpy Sep 19, 2005 by convertcode.py
|
||||
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
import functools
|
||||
import warnings
|
||||
|
||||
__all__ = ['iscomplexobj', 'isrealobj', 'imag', 'iscomplex',
|
||||
'isreal', 'nan_to_num', 'real', 'real_if_close',
|
||||
'typename', 'asfarray', 'mintypecode', 'asscalar',
|
||||
'common_type']
|
||||
|
||||
import numpy.core.numeric as _nx
|
||||
from numpy.core.numeric import asarray, asanyarray, isnan, zeros
|
||||
from numpy.core.overrides import set_module
|
||||
from numpy.core import overrides
|
||||
from .ufunclike import isneginf, isposinf
|
||||
|
||||
|
||||
array_function_dispatch = functools.partial(
|
||||
overrides.array_function_dispatch, module='numpy')
|
||||
|
||||
|
||||
_typecodes_by_elsize = 'GDFgdfQqLlIiHhBb?'
|
||||
|
||||
|
||||
@set_module('numpy')
|
||||
def mintypecode(typechars, typeset='GDFgdf', default='d'):
|
||||
"""
|
||||
Return the character for the minimum-size type to which given types can
|
||||
be safely cast.
|
||||
|
||||
The returned type character must represent the smallest size dtype such
|
||||
that an array of the returned type can handle the data from an array of
|
||||
all types in `typechars` (or if `typechars` is an array, then its
|
||||
dtype.char).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
typechars : list of str or array_like
|
||||
If a list of strings, each string should represent a dtype.
|
||||
If array_like, the character representation of the array dtype is used.
|
||||
typeset : str or list of str, optional
|
||||
The set of characters that the returned character is chosen from.
|
||||
The default set is 'GDFgdf'.
|
||||
default : str, optional
|
||||
The default character, this is returned if none of the characters in
|
||||
`typechars` matches a character in `typeset`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
typechar : str
|
||||
The character representing the minimum-size type that was found.
|
||||
|
||||
See Also
|
||||
--------
|
||||
dtype, sctype2char, maximum_sctype
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.mintypecode(['d', 'f', 'S'])
|
||||
'd'
|
||||
>>> x = np.array([1.1, 2-3.j])
|
||||
>>> np.mintypecode(x)
|
||||
'D'
|
||||
|
||||
>>> np.mintypecode('abceh', default='G')
|
||||
'G'
|
||||
|
||||
"""
|
||||
typecodes = [(isinstance(t, str) and t) or asarray(t).dtype.char
|
||||
for t in typechars]
|
||||
intersection = [t for t in typecodes if t in typeset]
|
||||
if not intersection:
|
||||
return default
|
||||
if 'F' in intersection and 'd' in intersection:
|
||||
return 'D'
|
||||
l = [(_typecodes_by_elsize.index(t), t) for t in intersection]
|
||||
l.sort()
|
||||
return l[0][1]
|
||||
|
||||
|
||||
def _asfarray_dispatcher(a, dtype=None):
|
||||
return (a,)
|
||||
|
||||
|
||||
@array_function_dispatch(_asfarray_dispatcher)
|
||||
def asfarray(a, dtype=_nx.float_):
|
||||
"""
|
||||
Return an array converted to a float type.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
a : array_like
|
||||
The input array.
|
||||
dtype : str or dtype object, optional
|
||||
Float type code to coerce input array `a`. If `dtype` is one of the
|
||||
'int' dtypes, it is replaced with float64.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
The input `a` as a float ndarray.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.asfarray([2, 3])
|
||||
array([ 2., 3.])
|
||||
>>> np.asfarray([2, 3], dtype='float')
|
||||
array([ 2., 3.])
|
||||
>>> np.asfarray([2, 3], dtype='int8')
|
||||
array([ 2., 3.])
|
||||
|
||||
"""
|
||||
if not _nx.issubdtype(dtype, _nx.inexact):
|
||||
dtype = _nx.float_
|
||||
return asarray(a, dtype=dtype)
|
||||
|
||||
|
||||
def _real_dispatcher(val):
|
||||
return (val,)
|
||||
|
||||
|
||||
@array_function_dispatch(_real_dispatcher)
|
||||
def real(val):
|
||||
"""
|
||||
Return the real part of the complex argument.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
val : array_like
|
||||
Input array.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray or scalar
|
||||
The real component of the complex argument. If `val` is real, the type
|
||||
of `val` is used for the output. If `val` has complex elements, the
|
||||
returned type is float.
|
||||
|
||||
See Also
|
||||
--------
|
||||
real_if_close, imag, angle
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> a = np.array([1+2j, 3+4j, 5+6j])
|
||||
>>> a.real
|
||||
array([ 1., 3., 5.])
|
||||
>>> a.real = 9
|
||||
>>> a
|
||||
array([ 9.+2.j, 9.+4.j, 9.+6.j])
|
||||
>>> a.real = np.array([9, 8, 7])
|
||||
>>> a
|
||||
array([ 9.+2.j, 8.+4.j, 7.+6.j])
|
||||
>>> np.real(1 + 1j)
|
||||
1.0
|
||||
|
||||
"""
|
||||
try:
|
||||
return val.real
|
||||
except AttributeError:
|
||||
return asanyarray(val).real
|
||||
|
||||
|
||||
def _imag_dispatcher(val):
|
||||
return (val,)
|
||||
|
||||
|
||||
@array_function_dispatch(_imag_dispatcher)
|
||||
def imag(val):
|
||||
"""
|
||||
Return the imaginary part of the complex argument.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
val : array_like
|
||||
Input array.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray or scalar
|
||||
The imaginary component of the complex argument. If `val` is real,
|
||||
the type of `val` is used for the output. If `val` has complex
|
||||
elements, the returned type is float.
|
||||
|
||||
See Also
|
||||
--------
|
||||
real, angle, real_if_close
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> a = np.array([1+2j, 3+4j, 5+6j])
|
||||
>>> a.imag
|
||||
array([ 2., 4., 6.])
|
||||
>>> a.imag = np.array([8, 10, 12])
|
||||
>>> a
|
||||
array([ 1. +8.j, 3.+10.j, 5.+12.j])
|
||||
>>> np.imag(1 + 1j)
|
||||
1.0
|
||||
|
||||
"""
|
||||
try:
|
||||
return val.imag
|
||||
except AttributeError:
|
||||
return asanyarray(val).imag
|
||||
|
||||
|
||||
def _is_type_dispatcher(x):
|
||||
return (x,)
|
||||
|
||||
|
||||
@array_function_dispatch(_is_type_dispatcher)
|
||||
def iscomplex(x):
|
||||
"""
|
||||
Returns a bool array, where True if input element is complex.
|
||||
|
||||
What is tested is whether the input has a non-zero imaginary part, not if
|
||||
the input type is complex.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like
|
||||
Input array.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray of bools
|
||||
Output array.
|
||||
|
||||
See Also
|
||||
--------
|
||||
isreal
|
||||
iscomplexobj : Return True if x is a complex type or an array of complex
|
||||
numbers.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.iscomplex([1+1j, 1+0j, 4.5, 3, 2, 2j])
|
||||
array([ True, False, False, False, False, True])
|
||||
|
||||
"""
|
||||
ax = asanyarray(x)
|
||||
if issubclass(ax.dtype.type, _nx.complexfloating):
|
||||
return ax.imag != 0
|
||||
res = zeros(ax.shape, bool)
|
||||
return res[()] # convert to scalar if needed
|
||||
|
||||
|
||||
@array_function_dispatch(_is_type_dispatcher)
|
||||
def isreal(x):
|
||||
"""
|
||||
Returns a bool array, where True if input element is real.
|
||||
|
||||
If element has complex type with zero complex part, the return value
|
||||
for that element is True.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like
|
||||
Input array.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray, bool
|
||||
Boolean array of same shape as `x`.
|
||||
|
||||
See Also
|
||||
--------
|
||||
iscomplex
|
||||
isrealobj : Return True if x is not a complex type.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.isreal([1+1j, 1+0j, 4.5, 3, 2, 2j])
|
||||
array([False, True, True, True, True, False])
|
||||
|
||||
"""
|
||||
return imag(x) == 0
|
||||
|
||||
|
||||
@array_function_dispatch(_is_type_dispatcher)
|
||||
def iscomplexobj(x):
|
||||
"""
|
||||
Check for a complex type or an array of complex numbers.
|
||||
|
||||
The type of the input is checked, not the value. Even if the input
|
||||
has an imaginary part equal to zero, `iscomplexobj` evaluates to True.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : any
|
||||
The input can be of any type and shape.
|
||||
|
||||
Returns
|
||||
-------
|
||||
iscomplexobj : bool
|
||||
The return value, True if `x` is of a complex type or has at least
|
||||
one complex element.
|
||||
|
||||
See Also
|
||||
--------
|
||||
isrealobj, iscomplex
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.iscomplexobj(1)
|
||||
False
|
||||
>>> np.iscomplexobj(1+0j)
|
||||
True
|
||||
>>> np.iscomplexobj([3, 1+0j, True])
|
||||
True
|
||||
|
||||
"""
|
||||
try:
|
||||
dtype = x.dtype
|
||||
type_ = dtype.type
|
||||
except AttributeError:
|
||||
type_ = asarray(x).dtype.type
|
||||
return issubclass(type_, _nx.complexfloating)
|
||||
|
||||
|
||||
@array_function_dispatch(_is_type_dispatcher)
|
||||
def isrealobj(x):
|
||||
"""
|
||||
Return True if x is a not complex type or an array of complex numbers.
|
||||
|
||||
The type of the input is checked, not the value. So even if the input
|
||||
has an imaginary part equal to zero, `isrealobj` evaluates to False
|
||||
if the data type is complex.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : any
|
||||
The input can be of any type and shape.
|
||||
|
||||
Returns
|
||||
-------
|
||||
y : bool
|
||||
The return value, False if `x` is of a complex type.
|
||||
|
||||
See Also
|
||||
--------
|
||||
iscomplexobj, isreal
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.isrealobj(1)
|
||||
True
|
||||
>>> np.isrealobj(1+0j)
|
||||
False
|
||||
>>> np.isrealobj([3, 1+0j, True])
|
||||
False
|
||||
|
||||
"""
|
||||
return not iscomplexobj(x)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def _getmaxmin(t):
|
||||
from numpy.core import getlimits
|
||||
f = getlimits.finfo(t)
|
||||
return f.max, f.min
|
||||
|
||||
|
||||
def _nan_to_num_dispatcher(x, copy=None):
|
||||
return (x,)
|
||||
|
||||
|
||||
@array_function_dispatch(_nan_to_num_dispatcher)
|
||||
def nan_to_num(x, copy=True):
|
||||
"""
|
||||
Replace NaN with zero and infinity with large finite numbers.
|
||||
|
||||
If `x` is inexact, NaN is replaced by zero, and infinity and -infinity
|
||||
replaced by the respectively largest and most negative finite floating
|
||||
point values representable by ``x.dtype``.
|
||||
|
||||
For complex dtypes, the above is applied to each of the real and
|
||||
imaginary components of `x` separately.
|
||||
|
||||
If `x` is not inexact, then no replacements are made.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : scalar or array_like
|
||||
Input data.
|
||||
copy : bool, optional
|
||||
Whether to create a copy of `x` (True) or to replace values
|
||||
in-place (False). The in-place operation only occurs if
|
||||
casting to an array does not require a copy.
|
||||
Default is True.
|
||||
|
||||
.. versionadded:: 1.13
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
`x`, with the non-finite values replaced. If `copy` is False, this may
|
||||
be `x` itself.
|
||||
|
||||
See Also
|
||||
--------
|
||||
isinf : Shows which elements are positive or negative infinity.
|
||||
isneginf : Shows which elements are negative infinity.
|
||||
isposinf : Shows which elements are positive infinity.
|
||||
isnan : Shows which elements are Not a Number (NaN).
|
||||
isfinite : Shows which elements are finite (not NaN, not infinity)
|
||||
|
||||
Notes
|
||||
-----
|
||||
NumPy uses the IEEE Standard for Binary Floating-Point for Arithmetic
|
||||
(IEEE 754). This means that Not a Number is not equivalent to infinity.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.nan_to_num(np.inf)
|
||||
1.7976931348623157e+308
|
||||
>>> np.nan_to_num(-np.inf)
|
||||
-1.7976931348623157e+308
|
||||
>>> np.nan_to_num(np.nan)
|
||||
0.0
|
||||
>>> x = np.array([np.inf, -np.inf, np.nan, -128, 128])
|
||||
>>> np.nan_to_num(x)
|
||||
array([ 1.79769313e+308, -1.79769313e+308, 0.00000000e+000,
|
||||
-1.28000000e+002, 1.28000000e+002])
|
||||
>>> y = np.array([complex(np.inf, np.nan), np.nan, complex(np.nan, np.inf)])
|
||||
>>> np.nan_to_num(y)
|
||||
array([ 1.79769313e+308 +0.00000000e+000j,
|
||||
0.00000000e+000 +0.00000000e+000j,
|
||||
0.00000000e+000 +1.79769313e+308j])
|
||||
"""
|
||||
x = _nx.array(x, subok=True, copy=copy)
|
||||
xtype = x.dtype.type
|
||||
|
||||
isscalar = (x.ndim == 0)
|
||||
|
||||
if not issubclass(xtype, _nx.inexact):
|
||||
return x[()] if isscalar else x
|
||||
|
||||
iscomplex = issubclass(xtype, _nx.complexfloating)
|
||||
|
||||
dest = (x.real, x.imag) if iscomplex else (x,)
|
||||
maxf, minf = _getmaxmin(x.real.dtype)
|
||||
for d in dest:
|
||||
_nx.copyto(d, 0.0, where=isnan(d))
|
||||
_nx.copyto(d, maxf, where=isposinf(d))
|
||||
_nx.copyto(d, minf, where=isneginf(d))
|
||||
return x[()] if isscalar else x
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def _real_if_close_dispatcher(a, tol=None):
|
||||
return (a,)
|
||||
|
||||
|
||||
@array_function_dispatch(_real_if_close_dispatcher)
|
||||
def real_if_close(a, tol=100):
|
||||
"""
|
||||
If complex input returns a real array if complex parts are close to zero.
|
||||
|
||||
"Close to zero" is defined as `tol` * (machine epsilon of the type for
|
||||
`a`).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
a : array_like
|
||||
Input array.
|
||||
tol : float
|
||||
Tolerance in machine epsilons for the complex part of the elements
|
||||
in the array.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
If `a` is real, the type of `a` is used for the output. If `a`
|
||||
has complex elements, the returned type is float.
|
||||
|
||||
See Also
|
||||
--------
|
||||
real, imag, angle
|
||||
|
||||
Notes
|
||||
-----
|
||||
Machine epsilon varies from machine to machine and between data types
|
||||
but Python floats on most platforms have a machine epsilon equal to
|
||||
2.2204460492503131e-16. You can use 'np.finfo(float).eps' to print
|
||||
out the machine epsilon for floats.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.finfo(float).eps
|
||||
2.2204460492503131e-16
|
||||
|
||||
>>> np.real_if_close([2.1 + 4e-14j], tol=1000)
|
||||
array([ 2.1])
|
||||
>>> np.real_if_close([2.1 + 4e-13j], tol=1000)
|
||||
array([ 2.1 +4.00000000e-13j])
|
||||
|
||||
"""
|
||||
a = asanyarray(a)
|
||||
if not issubclass(a.dtype.type, _nx.complexfloating):
|
||||
return a
|
||||
if tol > 1:
|
||||
from numpy.core import getlimits
|
||||
f = getlimits.finfo(a.dtype.type)
|
||||
tol = f.eps * tol
|
||||
if _nx.all(_nx.absolute(a.imag) < tol):
|
||||
a = a.real
|
||||
return a
|
||||
|
||||
|
||||
def _asscalar_dispatcher(a):
|
||||
return (a,)
|
||||
|
||||
|
||||
@array_function_dispatch(_asscalar_dispatcher)
|
||||
def asscalar(a):
|
||||
"""
|
||||
Convert an array of size 1 to its scalar equivalent.
|
||||
|
||||
.. deprecated:: 1.16
|
||||
|
||||
Deprecated, use `numpy.ndarray.item()` instead.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
a : ndarray
|
||||
Input array of size 1.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : scalar
|
||||
Scalar representation of `a`. The output data type is the same type
|
||||
returned by the input's `item` method.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.asscalar(np.array([24]))
|
||||
24
|
||||
|
||||
"""
|
||||
|
||||
# 2018-10-10, 1.16
|
||||
warnings.warn('np.asscalar(a) is deprecated since NumPy v1.16, use '
|
||||
'a.item() instead', DeprecationWarning, stacklevel=1)
|
||||
return a.item()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
_namefromtype = {'S1': 'character',
|
||||
'?': 'bool',
|
||||
'b': 'signed char',
|
||||
'B': 'unsigned char',
|
||||
'h': 'short',
|
||||
'H': 'unsigned short',
|
||||
'i': 'integer',
|
||||
'I': 'unsigned integer',
|
||||
'l': 'long integer',
|
||||
'L': 'unsigned long integer',
|
||||
'q': 'long long integer',
|
||||
'Q': 'unsigned long long integer',
|
||||
'f': 'single precision',
|
||||
'd': 'double precision',
|
||||
'g': 'long precision',
|
||||
'F': 'complex single precision',
|
||||
'D': 'complex double precision',
|
||||
'G': 'complex long double precision',
|
||||
'S': 'string',
|
||||
'U': 'unicode',
|
||||
'V': 'void',
|
||||
'O': 'object'
|
||||
}
|
||||
|
||||
@set_module('numpy')
|
||||
def typename(char):
|
||||
"""
|
||||
Return a description for the given data type code.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
char : str
|
||||
Data type code.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : str
|
||||
Description of the input data type code.
|
||||
|
||||
See Also
|
||||
--------
|
||||
dtype, typecodes
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> typechars = ['S1', '?', 'B', 'D', 'G', 'F', 'I', 'H', 'L', 'O', 'Q',
|
||||
... 'S', 'U', 'V', 'b', 'd', 'g', 'f', 'i', 'h', 'l', 'q']
|
||||
>>> for typechar in typechars:
|
||||
... print(typechar, ' : ', np.typename(typechar))
|
||||
...
|
||||
S1 : character
|
||||
? : bool
|
||||
B : unsigned char
|
||||
D : complex double precision
|
||||
G : complex long double precision
|
||||
F : complex single precision
|
||||
I : unsigned integer
|
||||
H : unsigned short
|
||||
L : unsigned long integer
|
||||
O : object
|
||||
Q : unsigned long long integer
|
||||
S : string
|
||||
U : unicode
|
||||
V : void
|
||||
b : signed char
|
||||
d : double precision
|
||||
g : long precision
|
||||
f : single precision
|
||||
i : integer
|
||||
h : short
|
||||
l : long integer
|
||||
q : long long integer
|
||||
|
||||
"""
|
||||
return _namefromtype[char]
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
#determine the "minimum common type" for a group of arrays.
|
||||
array_type = [[_nx.half, _nx.single, _nx.double, _nx.longdouble],
|
||||
[None, _nx.csingle, _nx.cdouble, _nx.clongdouble]]
|
||||
array_precision = {_nx.half: 0,
|
||||
_nx.single: 1,
|
||||
_nx.double: 2,
|
||||
_nx.longdouble: 3,
|
||||
_nx.csingle: 1,
|
||||
_nx.cdouble: 2,
|
||||
_nx.clongdouble: 3}
|
||||
|
||||
|
||||
def _common_type_dispatcher(*arrays):
|
||||
return arrays
|
||||
|
||||
|
||||
@array_function_dispatch(_common_type_dispatcher)
|
||||
def common_type(*arrays):
|
||||
"""
|
||||
Return a scalar type which is common to the input arrays.
|
||||
|
||||
The return type will always be an inexact (i.e. floating point) scalar
|
||||
type, even if all the arrays are integer arrays. If one of the inputs is
|
||||
an integer array, the minimum precision type that is returned is a
|
||||
64-bit floating point dtype.
|
||||
|
||||
All input arrays except int64 and uint64 can be safely cast to the
|
||||
returned dtype without loss of information.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
array1, array2, ... : ndarrays
|
||||
Input arrays.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : data type code
|
||||
Data type code.
|
||||
|
||||
See Also
|
||||
--------
|
||||
dtype, mintypecode
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.common_type(np.arange(2, dtype=np.float32))
|
||||
<type 'numpy.float32'>
|
||||
>>> np.common_type(np.arange(2, dtype=np.float32), np.arange(2))
|
||||
<type 'numpy.float64'>
|
||||
>>> np.common_type(np.arange(4), np.array([45, 6.j]), np.array([45.0]))
|
||||
<type 'numpy.complex128'>
|
||||
|
||||
"""
|
||||
is_complex = False
|
||||
precision = 0
|
||||
for a in arrays:
|
||||
t = a.dtype.type
|
||||
if iscomplexobj(a):
|
||||
is_complex = True
|
||||
if issubclass(t, _nx.integer):
|
||||
p = 2 # array_precision[_nx.double]
|
||||
else:
|
||||
p = array_precision.get(t, None)
|
||||
if p is None:
|
||||
raise TypeError("can't get common type for non-numeric array")
|
||||
precision = max(precision, p)
|
||||
if is_complex:
|
||||
return array_type[1][precision]
|
||||
else:
|
||||
return array_type[0][precision]
|
||||
@@ -0,0 +1,250 @@
|
||||
"""
|
||||
Module of functions that are like ufuncs in acting on arrays and optionally
|
||||
storing results in an output array.
|
||||
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
__all__ = ['fix', 'isneginf', 'isposinf']
|
||||
|
||||
import numpy.core.numeric as nx
|
||||
from numpy.core.overrides import array_function_dispatch, ENABLE_ARRAY_FUNCTION
|
||||
import warnings
|
||||
import functools
|
||||
|
||||
|
||||
def _deprecate_out_named_y(f):
|
||||
"""
|
||||
Allow the out argument to be passed as the name `y` (deprecated)
|
||||
|
||||
In future, this decorator should be removed.
|
||||
"""
|
||||
@functools.wraps(f)
|
||||
def func(x, out=None, **kwargs):
|
||||
if 'y' in kwargs:
|
||||
if 'out' in kwargs:
|
||||
raise TypeError(
|
||||
"{} got multiple values for argument 'out'/'y'"
|
||||
.format(f.__name__)
|
||||
)
|
||||
out = kwargs.pop('y')
|
||||
# NumPy 1.13.0, 2017-04-26
|
||||
warnings.warn(
|
||||
"The name of the out argument to {} has changed from `y` to "
|
||||
"`out`, to match other ufuncs.".format(f.__name__),
|
||||
DeprecationWarning, stacklevel=3)
|
||||
return f(x, out=out, **kwargs)
|
||||
|
||||
return func
|
||||
|
||||
|
||||
def _fix_out_named_y(f):
|
||||
"""
|
||||
Allow the out argument to be passed as the name `y` (deprecated)
|
||||
|
||||
This decorator should only be used if _deprecate_out_named_y is used on
|
||||
a corresponding dispatcher fucntion.
|
||||
"""
|
||||
@functools.wraps(f)
|
||||
def func(x, out=None, **kwargs):
|
||||
if 'y' in kwargs:
|
||||
# we already did error checking in _deprecate_out_named_y
|
||||
out = kwargs.pop('y')
|
||||
return f(x, out=out, **kwargs)
|
||||
|
||||
return func
|
||||
|
||||
|
||||
if not ENABLE_ARRAY_FUNCTION:
|
||||
_fix_out_named_y = _deprecate_out_named_y
|
||||
|
||||
|
||||
@_deprecate_out_named_y
|
||||
def _dispatcher(x, out=None):
|
||||
return (x, out)
|
||||
|
||||
|
||||
@array_function_dispatch(_dispatcher, verify=False, module='numpy')
|
||||
@_fix_out_named_y
|
||||
def fix(x, out=None):
|
||||
"""
|
||||
Round to nearest integer towards zero.
|
||||
|
||||
Round an array of floats element-wise to nearest integer towards zero.
|
||||
The rounded values are returned as floats.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like
|
||||
An array of floats to be rounded
|
||||
y : ndarray, optional
|
||||
Output array
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray of floats
|
||||
The array of rounded numbers
|
||||
|
||||
See Also
|
||||
--------
|
||||
trunc, floor, ceil
|
||||
around : Round to given number of decimals
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.fix(3.14)
|
||||
3.0
|
||||
>>> np.fix(3)
|
||||
3.0
|
||||
>>> np.fix([2.1, 2.9, -2.1, -2.9])
|
||||
array([ 2., 2., -2., -2.])
|
||||
|
||||
"""
|
||||
# promote back to an array if flattened
|
||||
res = nx.asanyarray(nx.ceil(x, out=out))
|
||||
res = nx.floor(x, out=res, where=nx.greater_equal(x, 0))
|
||||
|
||||
# when no out argument is passed and no subclasses are involved, flatten
|
||||
# scalars
|
||||
if out is None and type(res) is nx.ndarray:
|
||||
res = res[()]
|
||||
return res
|
||||
|
||||
|
||||
@array_function_dispatch(_dispatcher, verify=False, module='numpy')
|
||||
@_fix_out_named_y
|
||||
def isposinf(x, out=None):
|
||||
"""
|
||||
Test element-wise for positive infinity, return result as bool array.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like
|
||||
The input array.
|
||||
y : array_like, optional
|
||||
A boolean array with the same shape as `x` to store the result.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
A boolean array with the same dimensions as the input.
|
||||
If second argument is not supplied then a boolean array is returned
|
||||
with values True where the corresponding element of the input is
|
||||
positive infinity and values False where the element of the input is
|
||||
not positive infinity.
|
||||
|
||||
If a second argument is supplied the result is stored there. If the
|
||||
type of that array is a numeric type the result is represented as zeros
|
||||
and ones, if the type is boolean then as False and True.
|
||||
The return value `out` is then a reference to that array.
|
||||
|
||||
See Also
|
||||
--------
|
||||
isinf, isneginf, isfinite, isnan
|
||||
|
||||
Notes
|
||||
-----
|
||||
NumPy uses the IEEE Standard for Binary Floating-Point for Arithmetic
|
||||
(IEEE 754).
|
||||
|
||||
Errors result if the second argument is also supplied when x is a scalar
|
||||
input, if first and second arguments have different shapes, or if the
|
||||
first argument has complex values
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.isposinf(np.PINF)
|
||||
array(True, dtype=bool)
|
||||
>>> np.isposinf(np.inf)
|
||||
array(True, dtype=bool)
|
||||
>>> np.isposinf(np.NINF)
|
||||
array(False, dtype=bool)
|
||||
>>> np.isposinf([-np.inf, 0., np.inf])
|
||||
array([False, False, True])
|
||||
|
||||
>>> x = np.array([-np.inf, 0., np.inf])
|
||||
>>> y = np.array([2, 2, 2])
|
||||
>>> np.isposinf(x, y)
|
||||
array([0, 0, 1])
|
||||
>>> y
|
||||
array([0, 0, 1])
|
||||
|
||||
"""
|
||||
is_inf = nx.isinf(x)
|
||||
try:
|
||||
signbit = ~nx.signbit(x)
|
||||
except TypeError:
|
||||
raise TypeError('This operation is not supported for complex values '
|
||||
'because it would be ambiguous.')
|
||||
else:
|
||||
return nx.logical_and(is_inf, signbit, out)
|
||||
|
||||
|
||||
@array_function_dispatch(_dispatcher, verify=False, module='numpy')
|
||||
@_fix_out_named_y
|
||||
def isneginf(x, out=None):
|
||||
"""
|
||||
Test element-wise for negative infinity, return result as bool array.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like
|
||||
The input array.
|
||||
out : array_like, optional
|
||||
A boolean array with the same shape and type as `x` to store the
|
||||
result.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
A boolean array with the same dimensions as the input.
|
||||
If second argument is not supplied then a numpy boolean array is
|
||||
returned with values True where the corresponding element of the
|
||||
input is negative infinity and values False where the element of
|
||||
the input is not negative infinity.
|
||||
|
||||
If a second argument is supplied the result is stored there. If the
|
||||
type of that array is a numeric type the result is represented as
|
||||
zeros and ones, if the type is boolean then as False and True. The
|
||||
return value `out` is then a reference to that array.
|
||||
|
||||
See Also
|
||||
--------
|
||||
isinf, isposinf, isnan, isfinite
|
||||
|
||||
Notes
|
||||
-----
|
||||
NumPy uses the IEEE Standard for Binary Floating-Point for Arithmetic
|
||||
(IEEE 754).
|
||||
|
||||
Errors result if the second argument is also supplied when x is a scalar
|
||||
input, if first and second arguments have different shapes, or if the
|
||||
first argument has complex values.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> np.isneginf(np.NINF)
|
||||
array(True, dtype=bool)
|
||||
>>> np.isneginf(np.inf)
|
||||
array(False, dtype=bool)
|
||||
>>> np.isneginf(np.PINF)
|
||||
array(False, dtype=bool)
|
||||
>>> np.isneginf([-np.inf, 0., np.inf])
|
||||
array([ True, False, False])
|
||||
|
||||
>>> x = np.array([-np.inf, 0., np.inf])
|
||||
>>> y = np.array([2, 2, 2])
|
||||
>>> np.isneginf(x, y)
|
||||
array([1, 0, 0])
|
||||
>>> y
|
||||
array([1, 0, 0])
|
||||
|
||||
"""
|
||||
is_inf = nx.isinf(x)
|
||||
try:
|
||||
signbit = nx.signbit(x)
|
||||
except TypeError:
|
||||
raise TypeError('This operation is not supported for complex values '
|
||||
'because it would be ambiguous.')
|
||||
else:
|
||||
return nx.logical_and(is_inf, signbit, out)
|
||||
@@ -0,0 +1,288 @@
|
||||
"""
|
||||
Standard container-class for easy multiple-inheritance.
|
||||
|
||||
Try to inherit from the ndarray instead of using this class as this is not
|
||||
complete.
|
||||
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
from numpy.core import (
|
||||
array, asarray, absolute, add, subtract, multiply, divide,
|
||||
remainder, power, left_shift, right_shift, bitwise_and, bitwise_or,
|
||||
bitwise_xor, invert, less, less_equal, not_equal, equal, greater,
|
||||
greater_equal, shape, reshape, arange, sin, sqrt, transpose
|
||||
)
|
||||
from numpy.compat import long
|
||||
|
||||
|
||||
class container(object):
|
||||
"""
|
||||
container(data, dtype=None, copy=True)
|
||||
|
||||
Standard container-class for easy multiple-inheritance.
|
||||
|
||||
Methods
|
||||
-------
|
||||
copy
|
||||
tostring
|
||||
byteswap
|
||||
astype
|
||||
|
||||
"""
|
||||
def __init__(self, data, dtype=None, copy=True):
|
||||
self.array = array(data, dtype, copy=copy)
|
||||
|
||||
def __repr__(self):
|
||||
if self.ndim > 0:
|
||||
return self.__class__.__name__ + repr(self.array)[len("array"):]
|
||||
else:
|
||||
return self.__class__.__name__ + "(" + repr(self.array) + ")"
|
||||
|
||||
def __array__(self, t=None):
|
||||
if t:
|
||||
return self.array.astype(t)
|
||||
return self.array
|
||||
|
||||
# Array as sequence
|
||||
def __len__(self):
|
||||
return len(self.array)
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self._rc(self.array[index])
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
self.array[index] = asarray(value, self.dtype)
|
||||
|
||||
def __abs__(self):
|
||||
return self._rc(absolute(self.array))
|
||||
|
||||
def __neg__(self):
|
||||
return self._rc(-self.array)
|
||||
|
||||
def __add__(self, other):
|
||||
return self._rc(self.array + asarray(other))
|
||||
|
||||
__radd__ = __add__
|
||||
|
||||
def __iadd__(self, other):
|
||||
add(self.array, other, self.array)
|
||||
return self
|
||||
|
||||
def __sub__(self, other):
|
||||
return self._rc(self.array - asarray(other))
|
||||
|
||||
def __rsub__(self, other):
|
||||
return self._rc(asarray(other) - self.array)
|
||||
|
||||
def __isub__(self, other):
|
||||
subtract(self.array, other, self.array)
|
||||
return self
|
||||
|
||||
def __mul__(self, other):
|
||||
return self._rc(multiply(self.array, asarray(other)))
|
||||
|
||||
__rmul__ = __mul__
|
||||
|
||||
def __imul__(self, other):
|
||||
multiply(self.array, other, self.array)
|
||||
return self
|
||||
|
||||
def __div__(self, other):
|
||||
return self._rc(divide(self.array, asarray(other)))
|
||||
|
||||
def __rdiv__(self, other):
|
||||
return self._rc(divide(asarray(other), self.array))
|
||||
|
||||
def __idiv__(self, other):
|
||||
divide(self.array, other, self.array)
|
||||
return self
|
||||
|
||||
def __mod__(self, other):
|
||||
return self._rc(remainder(self.array, other))
|
||||
|
||||
def __rmod__(self, other):
|
||||
return self._rc(remainder(other, self.array))
|
||||
|
||||
def __imod__(self, other):
|
||||
remainder(self.array, other, self.array)
|
||||
return self
|
||||
|
||||
def __divmod__(self, other):
|
||||
return (self._rc(divide(self.array, other)),
|
||||
self._rc(remainder(self.array, other)))
|
||||
|
||||
def __rdivmod__(self, other):
|
||||
return (self._rc(divide(other, self.array)),
|
||||
self._rc(remainder(other, self.array)))
|
||||
|
||||
def __pow__(self, other):
|
||||
return self._rc(power(self.array, asarray(other)))
|
||||
|
||||
def __rpow__(self, other):
|
||||
return self._rc(power(asarray(other), self.array))
|
||||
|
||||
def __ipow__(self, other):
|
||||
power(self.array, other, self.array)
|
||||
return self
|
||||
|
||||
def __lshift__(self, other):
|
||||
return self._rc(left_shift(self.array, other))
|
||||
|
||||
def __rshift__(self, other):
|
||||
return self._rc(right_shift(self.array, other))
|
||||
|
||||
def __rlshift__(self, other):
|
||||
return self._rc(left_shift(other, self.array))
|
||||
|
||||
def __rrshift__(self, other):
|
||||
return self._rc(right_shift(other, self.array))
|
||||
|
||||
def __ilshift__(self, other):
|
||||
left_shift(self.array, other, self.array)
|
||||
return self
|
||||
|
||||
def __irshift__(self, other):
|
||||
right_shift(self.array, other, self.array)
|
||||
return self
|
||||
|
||||
def __and__(self, other):
|
||||
return self._rc(bitwise_and(self.array, other))
|
||||
|
||||
def __rand__(self, other):
|
||||
return self._rc(bitwise_and(other, self.array))
|
||||
|
||||
def __iand__(self, other):
|
||||
bitwise_and(self.array, other, self.array)
|
||||
return self
|
||||
|
||||
def __xor__(self, other):
|
||||
return self._rc(bitwise_xor(self.array, other))
|
||||
|
||||
def __rxor__(self, other):
|
||||
return self._rc(bitwise_xor(other, self.array))
|
||||
|
||||
def __ixor__(self, other):
|
||||
bitwise_xor(self.array, other, self.array)
|
||||
return self
|
||||
|
||||
def __or__(self, other):
|
||||
return self._rc(bitwise_or(self.array, other))
|
||||
|
||||
def __ror__(self, other):
|
||||
return self._rc(bitwise_or(other, self.array))
|
||||
|
||||
def __ior__(self, other):
|
||||
bitwise_or(self.array, other, self.array)
|
||||
return self
|
||||
|
||||
def __pos__(self):
|
||||
return self._rc(self.array)
|
||||
|
||||
def __invert__(self):
|
||||
return self._rc(invert(self.array))
|
||||
|
||||
def _scalarfunc(self, func):
|
||||
if self.ndim == 0:
|
||||
return func(self[0])
|
||||
else:
|
||||
raise TypeError(
|
||||
"only rank-0 arrays can be converted to Python scalars.")
|
||||
|
||||
def __complex__(self):
|
||||
return self._scalarfunc(complex)
|
||||
|
||||
def __float__(self):
|
||||
return self._scalarfunc(float)
|
||||
|
||||
def __int__(self):
|
||||
return self._scalarfunc(int)
|
||||
|
||||
def __long__(self):
|
||||
return self._scalarfunc(long)
|
||||
|
||||
def __hex__(self):
|
||||
return self._scalarfunc(hex)
|
||||
|
||||
def __oct__(self):
|
||||
return self._scalarfunc(oct)
|
||||
|
||||
def __lt__(self, other):
|
||||
return self._rc(less(self.array, other))
|
||||
|
||||
def __le__(self, other):
|
||||
return self._rc(less_equal(self.array, other))
|
||||
|
||||
def __eq__(self, other):
|
||||
return self._rc(equal(self.array, other))
|
||||
|
||||
def __ne__(self, other):
|
||||
return self._rc(not_equal(self.array, other))
|
||||
|
||||
def __gt__(self, other):
|
||||
return self._rc(greater(self.array, other))
|
||||
|
||||
def __ge__(self, other):
|
||||
return self._rc(greater_equal(self.array, other))
|
||||
|
||||
def copy(self):
|
||||
""
|
||||
return self._rc(self.array.copy())
|
||||
|
||||
def tostring(self):
|
||||
""
|
||||
return self.array.tostring()
|
||||
|
||||
def byteswap(self):
|
||||
""
|
||||
return self._rc(self.array.byteswap())
|
||||
|
||||
def astype(self, typecode):
|
||||
""
|
||||
return self._rc(self.array.astype(typecode))
|
||||
|
||||
def _rc(self, a):
|
||||
if len(shape(a)) == 0:
|
||||
return a
|
||||
else:
|
||||
return self.__class__(a)
|
||||
|
||||
def __array_wrap__(self, *args):
|
||||
return self.__class__(args[0])
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
if attr == 'array':
|
||||
object.__setattr__(self, attr, value)
|
||||
return
|
||||
try:
|
||||
self.array.__setattr__(attr, value)
|
||||
except AttributeError:
|
||||
object.__setattr__(self, attr, value)
|
||||
|
||||
# Only called after other approaches fail.
|
||||
def __getattr__(self, attr):
|
||||
if (attr == 'array'):
|
||||
return object.__getattribute__(self, attr)
|
||||
return self.array.__getattribute__(attr)
|
||||
|
||||
#############################################################
|
||||
# Test of class container
|
||||
#############################################################
|
||||
if __name__ == '__main__':
|
||||
temp = reshape(arange(10000), (100, 100))
|
||||
|
||||
ua = container(temp)
|
||||
# new object created begin test
|
||||
print(dir(ua))
|
||||
print(shape(ua), ua.shape) # I have changed Numeric.py
|
||||
|
||||
ua_small = ua[:3, :5]
|
||||
print(ua_small)
|
||||
# this did not change ua[0,0], which is not normal behavior
|
||||
ua_small[0, 0] = 10
|
||||
print(ua_small[0, 0], ua[0, 0])
|
||||
print(sin(ua_small) / 3. * 6. + sqrt(ua_small ** 2))
|
||||
print(less(ua_small, 103), type(less(ua_small, 103)))
|
||||
print(type(ua_small * reshape(arange(15), shape(ua_small))))
|
||||
print(reshape(ua_small, (5, 3)))
|
||||
print(transpose(ua_small))
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user